How to Set Custom Authentication with Azure API Gateway
Here is everything you should know about Azure API Management, including its purpose, benefits, and custom authentication.
Join the DZone community and get the full member experience.Join For Free
This article shows an Azure API management policy sample that demonstrates how to secure API access by using an external authenticator encapsulating custom authentication logic.
Before we look into the implementation of Custom authentication with Azure API Management, we shall look at API management.
Azure API Management (APIM) helps organizations publish APIs to external, partner, and internal developers to unlock the potential of their data and services. APIM enables you to create and manage modern API gateways for existing backend services hosted anywhere.
Benefits of Using Azure API Management
- Use advanced security policies like JWT tokens, certificates, and other credentials
- Secures backend services by gating access with API keys.
- Prevents Denial of Service (DOS) attacks by using throttling
- And many other benefits
The Architecture of APIM:
Azure API management is on top of our three back-end APIs (Orders API, Catalog API, and Marketing APIs). Every call to these back-end APIs goes through Azure API management service.
We want to implement custom authentication in the project wherein authentication is done through a third-party authentication server. We want every incoming request to be validated against the authentication server, so each request should be redirected to https://auth.authprovider.com/auth and have the token validated. If the token is valid then let it proceed with the request or else send 401.
How to Secure API Access Using External Authorizer Custom Authentication Logic
External authenticator evaluates only the information contained within the Authorization header. Alternatively, for example, a full copy of the incoming request can be forwarded to the authenticator by setting “mode” to copy in the send-request policy.
External authenticator responds with the status that is set to 200 OK if authentication was successful and 401 Unauthorized if it wasn’t.
To use API Management, we need to create APIs. Each API consists of one or more operations, and each API can be added to one or more products. To use an API, developers subscribe to a product that contains that API, and then they can call the API’s operation, subject to any usage policies that may be in effect using the Azure portal.
Create a New Service
From the Azure portal menu, select Create a resource. You can also select Create a resource on the Azure Home page.
On the New page, select Integration > API Management.
In the API Management service page, enter settings. It will take some minutes to create the instance of service. Once it is ready, we will be able to add APIs and apply policies on those APIs.
Go to Your API Management Instance
Once, API Management service is deployed and status online. We will have the below screen and create new APIs.
Now, I already have an Orders API that is open and does not have any authentication mechanism. So, anyone who has the URL of this API can call this and view the list of orders in the response. See the request below done using Postman:
To add the policy in the orders endpoint, we need to go to the Inbound Processing section and click on the icon as highlighted in the above screenshot to set the policy.
To authenticate the request using custom auth. We need an external authorizer’s URL (e.g. https://auth.authprovider.com/auth) where we need to redirect the request first and check the response code (200 OK) to verify the authentication of the request.
Before redirecting the request to the authentication provider, we need to check the Authentication header. If it is present, then only redirect; otherwise, respond with 401 Unauthorized. See the policy below to verify this.
After validating the request header, we need to forward the request to the authentication server using the below code:
In the above screen, we have stored the response of the request using this:
And we are extracting the response to get the status code of the authorizer’s response like:
<set-variable name=”status” value=”@(((IResponse)context.Variables[“authResponse”]).StatusCode)” />
So, we will have a status variable that contains the status code of the authentication server response. And we need to check the status code that is set to 200 OK if authorization was successful and 401 Unauthorized if it wasn’t.
That’s it! We are done with our APIM policy and now the order endpoint request will be first redirected to the external authorizer endpoint and based on the status code of response it will call our endpoint.
Inbound policy: You can see the full policy code here.
<policies> <inbound> <base /> <!-- Ensure presence of Authorization header --> <choose> <when condition="@(!context.Request.Headers.ContainsKey("Authorization"))"> <return-response> <set-status code="401" reason="Unauthorized" /> <set-header name="WWW-Authenticate" exists-action="append"> <value>@("Bearer realm="+context.Request.OriginalUrl.Host)</value> </set-header> </return-response> </when> </choose> <!-- Check for cached authorization status for the subject <cache-lookup-value key="@(context.Request.Headers.GetValueOrDefault("Authorization"))" variable-name="status" /> --> <choose> <!-- If a cache miss call external authorizer --> <when condition="@(!context.Variables.ContainsKey("status"))"> <!-- Invoke --> <send-request mode="new" response-variable-name="authResponse" timeout="10" ignore-error="false"> <set-url>https://api.gruber-logistics.dev/user_company_links?CRM_company_code=86681</set-url> <set-method>GET</set-method> <set-header name="X-ZUMO-AUTH" exists-action="override"> <value>@(context.Request.Headers.GetValueOrDefault("Authorization"))</value> </set-header> </send-request> <!-- Extract authorization status from authorizer's response --> <set-variable name="status" value="@(((IResponse)context.Variables["authResponse"]).StatusCode)" /> <!-- Cache authorization result <cache-store-value key="@(context.Request.Headers.GetValueOrDefault("Authorization"))" value="@((string)context.Variables["status"])" duration="5" /> --> </when> </choose> <!-- Authorize the request --> <choose> <when condition="@((int)context.Variables["status"] == 200)" /> <otherwise> <return-response> <set-status code="401" reason="UnAuthorized" /> <set-body>@(((IResponse)context.Variables["authResponse"]).Body.As<JObject>(preserveContent: true).ToString())</set-body> </return-response> </otherwise> </choose> </inbound> <backend> <base /> </backend> <outbound> <base /> </outbound> <on-error> <base /> </on-error> </policies>
Published at DZone with permission of Brijesh Patel. See the original article here.
Opinions expressed by DZone contributors are their own.