azureoauth-2.0policiesapim

Use azure Apim to Call an Api that uses OAuth2 token


With Apim i'm trying to call a backend Api that needs a OAuth2 validation. This question are more or less similair to this: Azure API Management: Oauth2 with backend API But there are no good answer here...

I have been reading alot about policies and caching. But can't seem to set it up correctly. I hope to be able to cal the apim, and then the apim calls the backend api to get a token and with that token call an Api to get some output data. I also found one where i had to setup some policies in the backend-part.. Can anyone help me set up the policies ?

my policy is like:

<policies>
    <inbound>
        <base />
        <set-variable name="originBearer" value="@(context.Request.Headers.GetValueOrDefault("Authorization", "empty_token").Split(' ')[0].ToString())" />
        <send-request ignore-error="true" timeout="20" response-variable-name="bearerToken" mode="new">
            <set-url>{{lookupAccessTokenUrl}}</set-url>
            <set-method>GET</set-method>
            <set-header name="Content-Type" exists-action="override">
                <value>application/x-www-form-urlencoded</value>
            </set-header>
            <set-body>@{
                    return "client_id={{HLR-app-client-id}}&scope={{HLR-scope}}&client_secret={{HLR-secret}}&assertion="+(string)context.Variables["originBearer"]+"&grant_type=urn:ietf:params:oauth:grant-type:client_credentials&requested_token_use=on_behalf_of";
            }</set-body>
        </send-request>
        <set-variable name="requestResponseToken" value="@((String)((IResponse)context.Variables["bearerToken"]).Body.As<JObject>()["access_token"])" />
        <set-header name="Authorization" exists-action="override">
            <value>@("Bearer " + (string)context.Variables["requestResponseToken"])</value>
        </set-header>
    </inbound>
    <backend>
        <base />
    </backend>
    <outbound>
        <base />
    </outbound>
    <on-error>
        <base />
    </on-error>
</policies>

Solution

  • I found the answer to my own Question :-) I try to comment on each line, but if you take alle the code and put it together you get a policy to handle Oauth2 in a backend api.

    In the inbound section, the cache-lookup-value Assigns the value in cache to the context variable called “bearerToken”. On first entry, the cache value will be null and the variable will not be created.

    <inbound>
    <cache-lookup-value key="cacheAccessToken" variable-name="bearerToken" />
    

    Create a variable that contains clientid and secret - needed to call the api

        <set-variable name="user-password" value="{{HLR-Clientid}}:{{HLR-Secret}}" 
    />
        <choose>
    

    Checks if the context variable collection contains a key called “bearerToken” and if not found executes the code between the opening and closing “” XML elements.

    <when condition="@(!context.Variables.ContainsKey("bearerToken"))">
    

    Initiates the request to the OAuth endpoint with a response timeout of 20 seconds. This will put the response message into the variable called “oauthResponse”

    <send-request mode="new" response-variable-name="oauthResponse" timeout="20" ignore-error="false">
    <set-url>{{lookupAccessTokenUrl}}</set-url>
    <set-method>POST</set-method>
    <set-header name="Content-Type" exists-action="override">
    <value>application/x-www-form-urlencoded</value>
    </set-header>
    

    here you define your header Authorization and use the variable that contains clientid and password

    <set-header name="Authorization" exists-action="override">
    <value>@("Basic " +  system.Convert.ToBase64String(Encoding.UTF8.GetBytes((string)context.Variables["user-password"])))</value>
    </set-header>
    <set-body>@("grant_type=client_credentials&scope={{HLR-Scope}}")</set-body>
    </send-request>
    

    Casts the response as a JSON object to allow the retrieval of the “access_token” value using an indexer and assigns it to the context variable “accessToken”.

    <set-variable name="AccessToken" value="@((string)((IResponse)context.Variables["oauthResponse"]).Body.As<JObject>()["access_token"])" />
    

    Store result in cache and where we add the contents of the variable “accessToken” into cache for a period of 3600 seconds.

    <cache-store-value key="cacheAccessToken" value="@((string)context.Variables["AccessToken"])" duration="3600" />
    

    Set the variable in a context-variable, then it can be used right now

    <set-variable name="bearerToken" value="@((string)context.Variables["AccessToken"])" />
    </when>
    </choose>
    <base />
    </inbound>
    
    <backend>
        <!--Creates the request to the backend web service. Here we are placing the response from the web service into the variable called “transferWSResponse”.-->
        <send-request mode="copy" response-variable-name="transferWSResponse" timeout="60" ignore-error="false">
            <set-method>GET</set-method>
            <!--Is the creating the “Authorization” header to be sent with the request.-->
            <set-header name="Authorization" exists-action="override">
                <value>@("Bearer " + (string)context.Variables["bearerToken"])</value>
            </set-header>
            <!--Removes the APIM subscription from being forwarded to the backend web service.-->
            <set-header name="Ocp-Apim-Subscription-Key" exists-action="delete" />
            <set-header name="Content-Type" exists-action="override">
                <value>application/json</value>
            </set-header>
        </send-request>
    </backend>
    
    
    <outbound>
        <!--Now we need to return the response message from the backend web service to the caller. This is done in the “<outbound>” policy section. Here we just simply return the value of the variable “transferWSResponse” back to the caller-->
        <return-response response-variable-name="transferWSResponse" />
        <base />
    </outbound>
    <on-error>
        <base />
    </on-error>
    </policies>