0
votes

Having Azure API Gateway with an exteral IdP (Okta) we setup a simple and working setup. The API Gateway is able to authenticate and authorize the JWT token and call the backend service (App Logic or Azure function).

Next to the invoking the backend services, the API Gateway can pass claims from the JWT token

    <validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="No JWT token" require-expiration-time="true" require-scheme="Bearer" require-signed-tokens="true" clock-skew="10" output-token-variable-name="jwttoken">

    <set-header name="jwt-token" exists-action="append">
        <value><![CDATA[@(context.Variables.ContainsKey("jwttoken") ? (((Jwt)(context.Variables["jwttoken"])).Subject) : "") ]]></value>
    </set-header>

The backend services (AppLogic) are authorized using its SAS token, so we have to remove the Authorization header. I'm considering to send the JWT token to the backend anyway, but so far I found no way to do so (serialize the jwttoken variable, the API GW doesn't allow to call the .ToString() method).

Q: Is there / How do I send the original JWT token to the backend (in another header?)

2

2 Answers

1
votes

Jwt.TryParse can be used to break up the JWT token and pass on in another header in clear text:

<policies>
    <inbound>
        <base />
        <set-header name="parsed-token" exists-action="override">
            <value>@{
                string parsedToken = "error";
                string tokenHeader = context.Request.Headers.GetValueOrDefault("jwt-token", "");
                if (tokenHeader?.Length > 0)
                {
                    Jwt jwt;
                    if (tokenHeader.TryParseJwt(out jwt))
                    {
                        foreach(var claim in jwt.Claims)
                        {
                            parsedToken += claim.Key + ":" + string.Join("-",claim.Value) + ";";
                        }
                    }
                    }
                    return parsedToken;
                }</value>
        </set-header>
    </inbound>
    <backend>
        <base />
    </backend>
    <outbound>
        <base />
    </outbound>
    <on-error>
        <base />
    </on-error>
</policies>

For a sample token from https://jwt.io/#debugger-io this would give you headers like:

"jwt-token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c",
"parsed-token": "errorsub:1234567890;name:John Doe;iat:1516239022;",

I still cannot find proper documentation for class Jwt used in Azure API policy expressions - this class does not seem to have a ToString().

1
votes

Since your backend expects SAS token at some point in your policy you have set-header policy to set SAS token, correct? Well, then just copy value from Authorization header before you overwrite it:

<set-header name="jwt" exists-action="override">
    <value>@(context.Request.Headers.GetValueOrDefault("Authorization"))</value>
</set-header>