Azure API Management is a hybrid, multi-cloud management service for APIs onAzure; ensuring a complete abstraction of backend APIs and its complexities from the consumer of the APIs. This allows API developers to Securely expose APIs to various types of API consumers with varying degree of access control, observability and protection mechanisms available out-of-the-box.
Azure API Management has deep integrations with Azure AD which in turn has support for with the OAuth 2.0 & OpenID Connect through Microsoft identity platform. These two powerful, feature-rich resources can be leveraged to secure backend APIs without adding any code or logic within the APIs itself; thus making the Security of APIs clean, flexible and reusable
A detailed overview of configurations in Azure AD for OAuth 2.0 and OpenID Connect
Deep look at the various protection mechanisms available in Microsoft Identity platform
How to integrate API Management with OAuth 2.0 and/or OpenID Connect
Leverage built-in Policies in Azure API Management to secure the backend APIs
Follow these Steps to register
Let us call this ServerApp to better correlate
Go to Manifest section of the app and update
acceptMappedClaims to true - This is needed to make sure that the Associated Groups are returned as part of the OAuth 2.0 or OpenID token
groupMembershipClaims option to SecurityGroup
Configure API Permission section
Add/Modify Token Configuration section
Optional and Group claims can be added
App Roles can also be included in the Token Configuration
Roles will be granted permission by Administrator
Administrator will then add Roles to Users/Groups
Roles are returned as part of the Token; Applications can use that to appropriate action
Go to Expose API section and Add Scope
Follow these Steps to register
Let us call this ClientApp to better correlate
Go to Authentication section and modify as below
Select Multi-tenant or Single-tenant option as per requirement
Configure as shown in the below screen shots; these are self-explanatory
This document uses Validate-JWT policy
Policy can be added at different levels
Global
Product
APIs
<policies>
<inbound>
<base />
<!--Check the validity of the Bearer Token-->
<validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="UnAuthorized">
<openid-config url="https://login.microsoftonline.com/<tenant-id>/.well-known/openid-configuration" />
</validate-jwt>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
Let us check the Audience value of token
Audience in JWT token is the Scope of the ClientApp as configured earlier
Create a Named value as - <aud> = api://<scope>
<policies>
<inbound>
<base />
<!--Check the validity of the Bearer Token-->
<validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="UnAuthorized">
<openid-config url="https://login.microsoftonline.com/<tenant-id>/.well-known/openid-configuration" />
<!--Check the claims of the Bearer Token-->
<required-claims>
<claim name="aud" match="all">
<value>{{aud}}</value>
</claim>
</required-claims>
</validate-jwt>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
This can be extended to check for any Optional Claims or Group Claims as well
Additional information from Bearer Token can be sent to the backend APIs
Backend APIs can use it for some additional decision specific to the API based on the data returned in Token
<policies>
<inbound>
<base />
<!--Check the validity of the Bearer Token-->
<validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="UnAuthorized">
<openid-config url="https://login.microsoftonline.com/<tenant-id>/.well-known/openid-configuration" />
<!--Check the claims of the Bearer Token-->
<required-claims>
<claim name="aud" match="all">
<value>{{aud}}</value>
</claim>
</required-claims>
</validate-jwt>
<!--Extract AppId from Token and Add this to the request header-->
<set-header name="appid" exists-action="append">
<value>@{
string appid = "unknown";
string authHeader = context.Request.Headers.GetValueOrDefault("Authorization", "");
if (authHeader?.Length > 0)
{
string[] authHeaderParts = authHeader.Split(' ');
if (authHeaderParts?.Length == 2 && authHeaderParts[0].Equals("Bearer", StringComparison.InvariantCultureIgnoreCase))
{
Jwt jwt;
if (authHeaderParts[1].TryParseJwt(out jwt))
{
appid = jwt.Claims.GetValueOrDefault("appid", "unknown");
}
}
}
return appid;
}</value>
</set-header>
<!--Check appid value from Request Header and take decision-->
<choose>
<when condition="@(context.Request.Headers.GetValueOrDefault("appid", "unknown") != "{{appid}}")">
<set-backend-service base-url="<error url>" />
</when>
</choose>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
Recommended for Native Mobile Apps, Web Apps, SPAs which would connect to Azure from Device or Desktop
https://login.microsoftonline.com/{{tenantId}}/oauth2/v2.0/authorize?client_id={{clientId}}&response_type=code&redirect_uri=https://login.microsoftonline.com/common/oauth2/nativeclient&response_mode=query&scope={{scope}}/.default&prompt=login
Key | Value |
---|---|
client_id | <Client Id> of the ClientApp |
response_type | code |
redirect_uri | https://login.microsoftonline.com/common/oauth2/nativeclient |
response_mode | query |
scope | <Scope> of the ClientApp |
prompt | login |
Key | Value |
---|---|
code | Authorization Code |
state | (Optional) state parameter if sent in the Request |
https://login.microsoftonline.com/{{tenantId}}/oauth2/v2.0/token
Key | Value |
---|---|
client_id | <Client Id> of the ClientApp |
code | <Authorization Code> |
redirect_uri | https://login.microsoftonline.com/common/oauth2/nativeclient |
response_mode | query |
scope | openid offline_access profile |
grant_type | authorization_code |
Key | Value |
---|---|
token_type | Bearer |
scope | <All Scopes> |
expires_in | <value> |
ext_expires_in | <value> |
access_token | <Access Token> |
refresh_token | <Refresh Token> |
id_token | (Optional) <Id Token> |
Primarily for Azure to Azure calls
https://login.microsoftonline.com/{{tenantId}}/oauth2/v2.0/token
Key | Value |
---|---|
client_id | <Client Id> of the ClientApp |
client_secret | <Client Secret> of the ClientApp |
scope | <Scope> of the ClientApp |
grant_type | client_credentials |
Key | Value |
---|---|
token_type | Bearer |
expires_in | <value> |
ext_expires_in | <value> |
access_token | <Access Token> |
Primarily for CLI based Login
https://login.microsoftonline.com/{{tenantId}}/oauth2/v2.0/devicecode
Key | Value |
---|---|
client_id | <Client Id> of the ClientApp |
scope | <Scope> of the ClientApp |
Key | Value |
---|---|
device_code | Device Code |
user_code | Short string to identify the session |
verification_uri | Users need to use this URI pasting the user_code |
expires_in | <value> |
interval | <value> |
message | Human readable Message to the User |
https://login.microsoftonline.com/{{tenantId}}/oauth2/v2.0/token
Key | Value |
---|---|
client_id | <Client Id> of the ClientApp |
device_code | <Device Code> |
grant_type | urn:ietf:params:oauth:grant-type:device_code |
Key | Value |
---|---|
token_type | Bearer |
scope | <All Scopes> |
expires_in | <value> |
access_token | <Access Token> |
refresh_token | <Refresh Token> |
id_token | (Optional) <Id Token> |
Extends the OAuth 2.0 authorization protocol
Single sign-on using OAuth
ID token - allows the client to verify the identity of the user
https://login.microsoftonline.com/{{tenantId}}/oauth2/v2.0/authorize?client_id={{clientId}}&response_type=id_token%20token&redirect_uri=https://login.microsoftonline.com/common/oauth2/nativeclient&response_mode=query&scope=openid&prompt...{{value}}
Key | Value |
---|---|
client_id | <Client Id> of the ClientApp |
response_type | id_token token |
redirect_uri | https://login.microsoftonline.com/common/oauth2/nativeclient |
response_mode | form_post |
scope | openid |
prompt | login |
nonce | <value> |
Key | Value |
---|---|
token_type | Bearer |
scope | <All Scopes> |
expires_in | <value> |
ext_expires_in | <value> |
access_token | <Access Token> |
refresh_token | <Refresh Token> |
id_token | (Optional) <Id Token> |
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.