Microsoft Identity
-
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
Configure Azure AD
Register an Application to represent the Back end APIs
-
Follow these 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
-
API Permission
Token Configuration section
-
Optional and Group
-
Follow these to register
-
Let us call this ClientApp to better correlate
Authentication section and modify as below
-
Select Multi-tenant or Single-tenant
-
Configure as shown in the below screen shots; these are self-explanatory
-
-
This document uses 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/3851f269-b22b-4de6-97d6-aa9fe60fe301/.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/3851f269-b22b-4de6-97d6-aa9fe60fe301/.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/3851f269-b22b-4de6-97d6-aa9fe60fe301/.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> -
Authorization Code
-
Recommended for Native Mobile Apps, Web Apps, SPAs which would connect to Azure from Device or Desktop
Request
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 |
Response
Value | |
---|---|
code | Authorization Code |
state | (Optional) state parameter if sent in the Request |
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 |
Response
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> |
Request
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 |
Response
Key | Value |
---|---|
token_type | Bearer |
expires_in | <value> |
ext_expires_in | <value> |
access_token | <Access Token> |
-
Primarily for CLI based Login
Request
https://login.microsoftonline.com/{{tenantId}}/oauth2/v2.0/devicecode
Key | Value |
---|---|
client_id | <Client Id> of the ClientApp |
scope | <Scope> of the ClientApp |
Response
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 |
Fetch Access Token and Refresh Token
Request
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 |
Response
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
Request
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=login&nonce={{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> |
Response
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> |