简体   繁体   中英

Caching JWKS from Identity Provider using Azure API management for validating JWT

The code below validates JWT token by downloading JWKS every time it validates each request following this

    <validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="Error: expired token or invalid token" require-expiration-time="true" require-scheme="Bearer" require-signed-tokens="true">
        <openid-config url="https://IdentityProvider/oidc/.well-known/openid-configuration" />
        <audiences>
            <audience>aud id</audience>
        </audiences>
    </validate-jwt>

My question is how to cache the JWKS from the example link below to avoid downloading it every time, and without hard-coding the JWKS, since it is rotated regularly.

https://demo.identityserver.io/.well-known/openid-configuration/jwks

https://openid-connect-eu.onelogin.com/oidc/certs

Any code example and links for caching and validate JWT would be appreciated.

Below seems relevant but not a complete example.

https://docs.microsoft.com/en-us/azure/api-management/api-management-sample-cache-by-key

Update

Just to be clear, I want to cache the contents from JWKS of the links above to improve performance.

Checkout the below sample referred from here if that helps !

<policies>
    <inbound>
        <!-- Add your wcf relay address as the base URL below -->
        <set-backend-service base-url="" />
        <!-- verify if there is a relaytoken key stored in cache -->
        <cache-lookup-value key="@("relaytoken")" variable-name="relaytoken" />
        <choose>
            <!-- If there is no key stored in cache -->
            <when condition="@(!context.Variables.ContainsKey("relaytoken"))">
                <set-variable name="resourceUri" value="@(context.Request.Url.ToString())" />
                <!-- Retrieve Shared Access Policy key from  Name Value store -->
                <set-variable name="accessKey" value="{{accessKey}}" />
                <!-- Retrieve Shared Access Policy key name from  Name Value store -->
                <set-variable name="keyName" value="{{accessKeyName}}" />
                <!-- Generate the relaytoken key -->
                <set-variable name="relaytoken" value="@{
                    TimeSpan sinceEpoch = DateTime.UtcNow - new DateTime(1970, 1, 1);
                    string expiry =  Convert.ToString((int)sinceEpoch.TotalSeconds + 3600);
                    string resourceUri = (string)context.Variables["resourceUri"];
                    string stringToSign = Uri.EscapeDataString (resourceUri) + "\n" + expiry;
                    HMACSHA256 hmac = new HMACSHA256(Encoding.UTF8.GetBytes((string)context.Variables["accessKey"]));
                    string signature = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));
                    string sasToken = String.Format("SharedAccessSignature sr={0}&sig={1}&se={2}&skn={3}",
                    Uri.EscapeDataString(resourceUri), Uri.EscapeDataString(signature), expiry, context.Variables["keyName"]);
                    return sasToken;
                    }" />
                <!-- Store the relaytoken in the cache -->
                <cache-store-value key="relaytoken" value="@((string)context.Variables["relaytoken"])" duration="10" />
            </when>
        </choose>
        <!-- If the operation request uses json format, convert it to XML - Azure Relay expects XML format (based on WCF) -->
        <set-body template="liquid">
            <!-- set your body transformation here -->
        </set-body>
        <!-- Create the ServiceBusAuthorization header using the relaytoken as value -->
        <set-header name="ServiceBusAuthorization" exists-action="override">
            <value>@((string)context.Variables["relaytoken"])</value>
        </set-header>
        <!-- Set the content type to application/xml -->
        <set-header name="Content-Type" exists-action="override">
            <value>application/xml</value>
        </set-header>
        <base />
    </inbound>
    <backend>
        <base />
    </backend>
    <outbound>
    <!-- If the operation responses uses json format, convert it from XML - Azure Relay will return XML format (based on WCF) -->
        <set-body template="liquid">
            <!-- set your body transformation here -->
        </set-body>
        <!-- Set the content type to application/json -->
        <set-header name="Content-Type" exists-action="override">
            <value>application/json</value>
        </set-header>
    </outbound>
    <on-error>
        <base />
    </on-error>
</policies>

Azure API Management service has built-in support for HTTP response caching using the resource URL as the key ( https://github.com/toddkitta/azure-content/blob/master/articles/api-management/api-management-sample-cache-by-key.md ). What you could do is to set the openid-config url as an operation and control caching by yourself. Another approach could be by introducing an own caching service.

APIM will not download open id config for every request. It's downloaded, cached and automatically refreshed periodically, every hour if I recall correctly.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM