DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

Kohei Kawata
Kohei Kawata

Posted on • Updated on

Azure AD app configuration for Web API

Summary

In this article, I am tyring to describe how to configure for your own APIs Azure Active Directory authentication and authorization with .NET application on Azure App Service. Two patterns of authorization code flow and three patterns of client credential flow are discussed. Here is a sample code for .NET 6 auth API.

TOC

OAuth 2.0 flows

For your own API authentication and authorization, you register your app in Azure AD and use Microsoft Identity Platform that is compliant with OpenID Connect and OAuth 2.0 protocols. There are some grant flows such as implicit, hybrid, or device code flow. Here I want to focus on authorization code flow and client credential flow for Web APIs.

Authorization code flow

Authorization code flow requires you to log in as a Azure AD user and then request a token for a Web API. There are three steps.

  1. Request an authorization code
  2. Request an access token
  3. Send a request to a Web API with the token

Authorization code flow example

Image description

Client credential flow

Client credential flow does not require a Azure AD user but roles claim in the token. An alternative method without roles claim is ACL(Access Control List). In contrast with authorization code flow, client credential flow needs two steps.

  1. Request an access token
  2. Send a request to a Web API with the token

Client credential flow example

Image description

Configuration patterns

I want to discuss some of configuration patterns of authorization code flow and client credential flow.

  • Authorization code flow 1
  • AUthorization code flow 2
  • Client credential flow 1
  • Client credential flow 2
  • Client credential flow 3

For each pattern above, you have to configure four areas, Azure AD client, Azure AD backend, Client application, Backend API application.

Azure AD client/backend

  • Authentication
    • Platform
    • Redirect URIs
    • Front-channel logout URL
    • Access tokens
    • ID tokens
  • Secrets
  • API Permissions
    • Type (Delegated/Application)
    • Admin consent
  • Expose an API
    • Additional ID URI
    • Scope
    • Who can consent
    • Authorized client applications
  • App roles
    • Member types (User-Group/Application)
    • Value

Client application for HTTP request

  • Type (GET/POST)
  • Auth URL
  • Token URL
  • Client ID
  • Client secret
  • Scope

Backend API (.NET application)

  • Controller
    • Attributes
  • appsettings (AzureAd section)
    • Instance
    • Domain
    • ClientId
    • TenantId
    • CallbackPath
    • AllowWebApiToBeAuthorizedByACL
  • launchSettings
    • iisSettings/sslPort

Common configuration

  • Authorized client applications in Expose an API section is not needed for the patterns below.
  • Neither ID tokens nor Access tokens in Azure AD app Authentication section are required in the patterns below. The official explanation is below. It requires when using hybrid or implicit flow.

Request a token directly from the authorization endpoint. If the application has a single-page architecture (SPA) and doesn't use the authorization code flow, or if it invokes a web API via JavaScript, select both access tokens and ID tokens. For ASP.NET Core web apps and other web apps that use hybrid authentication, select only ID tokens.

Authorization code flow 1

  • Register only a backend app in Azure AD App Registration.
  • For authorization code flow, you need to determine scope. In this example, it uses access_as_user.
  • For authorization code flow, you need two endpoints
    • https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/authorize
    • https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token
  • For authorization code flow, you need to set up Redirect URIs. /signin-oidc is from CallbackPath in a backend API .NET appsettings, 44321 from sslPort in launchSettings.
  • HTTP request from the client application
    • Client ID: {clientId of BACKEND}
    • Client secret: {client secret of BACKEND}
    • Scope: api://{clientId of BACKEND}/access_as_user

Image description

Authorization code flow 2

  • Register both client and backend apps in Azure AD App Registration.
  • For authorization code flow, you need to determine scope. In this example, it uses access_as_user.
  • For authorization code flow, you need two endpoints
    • https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/authorize
    • https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token
  • For authorization code flow, you need to set up Redirect URIs. /signin-oidc is from CallbackPath in a backend API .NET appsettings, 44321 from sslPort in launchSettings.
  • In Azure AD client, set up Delegated permission of access_as_user backend API. You can grant admin consent in Azure AD, otherwise you are asked when logging in.
  • HTTP request from the client application
    • Client ID: {clientId of CLIENT}
    • Client secret: {client secret of CLIENT}
    • Scope: api://{clientId of BACKEND}/access_as_user

Image description

Client credential flow 1

  • Register only a backend app in Azure AD App Registration.
  • For client credential flow, you only need Additional ID URI set, not need to determine scope. For HTTP request from client, you use have to set api://{clientId}/.default
  • For client credential flow, you need only the token endpoint
    • https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token
  • For client credential flow without App roles, you need to set up AllowWebApiToBeAuthorizedByACL=true otherwise you would get an error.
  • HTTP request from the client application
    • Client ID: {clientId of BACKEND}
    • Client secret: {client secret of BACKEND}
    • Scope: api://{clientId of BACKEND}/.default

Image description

Client credential flow 2

  • Register both client and backend apps in Azure AD App Registration.
  • For client credential flow, you only need Additional ID URI set, not need to determine scope. For HTTP request from client, you use have to set api://{clientId}/.default
  • For client credential flow, you need only the token endpoint
    • https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token
  • For client credential flow without App roles, you need to set up AllowWebApiToBeAuthorizedByACL=true otherwise you would get an error.
  • This pattern does not require API Permissions setting even though it has both client and backend Azure AD apps.
  • HTTP request from the client application
    • Client ID: {clientId of CLIENT}
    • Client secret: {client secret of CLIENT}
    • Scope: api://{clientId of BACKEND}/.default

Image description

Client credential flow 3

  • Register both client and backend apps in Azure AD App Registration.
  • For client credential flow, you only need Additional ID URI set, not need to determine scope. For HTTP request from client, you use have to set api://{clientId}/.default
  • For client credential flow, you need only the token endpoint
    • https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token
  • You create App roles for the backend Azure AD app. In this example, the app role is Reader
  • Application permission has to be set in API Permissions of Azure AD client app. Admin consent should be set in Azure AD because this is a service login and does not have a browser to ask consent when logging in.
  • HTTP request from the client application
    • Client ID: {clientId of CLIENT}
    • Client secret: {client secret of CLIENT}
    • Scope: api://{clientId of BACKEND}/.default
  • In .NET application controller, you can set up an attribute [Authorize(Roles = "Reader")]. It works for [Authorize] as well.

Image description

Token examples

Header

JSON example

{
  "typ": "JWT",
  "alg": "RS256",
  "x5t": "Mr5-AUibfBii...",
  "kid": "Mr5-AUibfBii..."
}
Enter fullscreen mode Exit fullscreen mode

Description

Claim Description
typ Type
alg Algorithm
x5t Thumbprint for the public key
kid Same as x5t

Comparison of examples

Claim Example (Authorization code flow) Example (Client credential flow)
typ JWT ←
alg RS256 ←
x5t Mr5-AUibfBi... ←
kid Mr5-AUibfBi... ←

Payload

JSON example

{
  "aud": "api://xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "iss": "https://sts.windows.net/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/",
  "iat": 1640486334,
  "nbf": 1640486334,
  "exp": 1640490987,
  "acr": "1",
  "aio": "AUQAu/8TAAAAEWGo0AL...",
  "amr": [
    "wia"
  ],
  "appid": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "appidacr": "1",
  "email": "koheikawata@xxxxx.com",
  "family_name": "Kawata",
  "given_name": "koheikawata@xxxxx.com",
  "idp": "https://sts.windows.net/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/",
  "in_corp": "true",
  "ipaddr": "xx.xx.xxx.xx",
  "name": "koheikawata@xxxxx.com Kawata",
  "oid": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "rh": "0.AUoAT2_1IpDf1Ea7...",
  "scp": "access_as_user",
  "sub": "V2_FAxEN...",
  "tid": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "unique_name": "koheikawata@xxxxx.com",
  "uti": "nk9QA...",
  "ver": "1.0"
}
Enter fullscreen mode Exit fullscreen mode

Description

Claim Description
aud Recipient of token, audience
iss Issuer
iat Issued At. Timestamp
nbf Not before. Timestamp
exp Expiration. Timestamp
acr Authentication context class (Only access token)
aio Internal claim by Azure AD
amr How authenticated (wia: Windows Integrated Authentication)
appid Application ID (Only access token)
appidacr Public:0, Secret:1, Certificate:2 (Only access token)
email Email address (Only ID token)
family_name Last name (Only access token)
given_name First name (Only access token)
idp Identity provider
in_corp Corporate network (Only access token)
ipaddr IP address the user authenticated from (Only access token)
name Name of human readable value
oid Object ID of user or service principal
rh Internal claim by Azure
scp Scope (Only access token)
roles The set of permissions exposed by your application
sub Subject
tid Tenant ID
unique_name Name of human readable value
uti Internal claim by Azure
ver Version of the token

Comparison of examples

Claim Example (Authorization code flow) Example (Client credential flow)
aud api://{clientId} ←
iss https://sts.windows.net/{tenantId}/ ←
iat 1640271957 ←
nbf 1640271957 ←
exp 1640276399 ←
acr 1
aio AUQAu/8TAAAA1Uw... ←
amr wia
appid {clientId} ←
appidacr 1 ←
email koheikawata@xxxxx.com
family_name Kawata
given_name koheikawata@xxxxx.com
idp https://sts.windows.net/{tenantId}/ ←
in_corp TRUE
ipaddr xx.xx.xxx.xx
name koheikawata@xxxxx.com
oid {objectId} ←
rh 0.AUoAT2_1Ip... ←
scp access_as_user
roles Read
sub V2_FAxENmMoue5VT... {objectId}
tid {tenantId} ←
unique_name koheikawata@xxxxx.com
uti ZO37H... ←
ver 1 ←

Configuration summary

Image description

Top comments (0)

😍 Want to help the DEV Community feel more like a community? πŸ₯Ή

Head over to the Welcome Thread and greet some new community members!