Microsoft EntraID Apps for SPA and WEB API
This tutorial will register Microsoft EntraID applications (SPA and WEB_API) for OIDC authorization code flow with PKCE.
SPA (single-page application) is a public page that can sign in to users with Microsoft identity accounts and call backend WEB API service using bearer token with delegated scope issued to authenticated users to authorize API access. The SPA - is usually built using JS/Angular/React framework with Microsoft Authentication Library (MSAL), which supports authorization code flow in the browser instead of the implicit grant flow. WEB API - can be built using ASP.NET Core framework with "Microsoft.Identity.Web" authentication library, which can protect the API, check permissions and validate Azure Identity tokens for access.
Architecture
The diagram shows how OIDC flow works between apps
Elaboration on the above steps:
SPA performs the OAuth 2.0 authorization code flow with PKCE
SPA users sign in with Microsoft Identity accounts
Acquire an access token
Call WEB API that requires access tokens obtained from the Microsoft identity platform
EntraID Apps Registration
Two Azure EntraID applications must be registered. One for SPA (web-msal-spa) and another for WEB API (web-msal-api)
Register backend API service app (web-msal-api)
Navigate to the Azure portal and select the Microsoft Entra ID service.
Select the App Registrations blade on the left, then select New registration.
In the Register an application page that appears, enter your application's registration information:
In the Name section, enter a meaningful application name: web-msal-api
Under Supported account types, select Accounts in this organizational directory only
Select Register to create the application.
In the app's registration screen, select the Expose an API blade to the left to open the page where you can publish the permission as an API for which client applications can obtain access tokens for. The first thing that we need to do is to declare the unique resource URI that the clients will be using to obtain access tokens for this API. To declare an resource URI(Application ID URI), follow the following steps:
Select Add next to the Application ID URI to generate a URI that is unique for this app.
Accept the proposed Application ID URI (api://{clientId}) by selecting Save.
Publish Delegated Permissions
All APIs must publish a minimum of one scope, also called Delegated Permission, for the client apps to obtain an access token for a user successfully. To publish a scope, follow these steps:
Select Add a scope button open the Add a scope screen and Enter the values as indicated below:
For Scope name, use JWT.Read.
For Admin consent display name type in JWT.Read.
For Admin consent description type : Allows the app to read the signed-in user's JWT.
Keep State as Enabled.
Select the Add scope button on the bottom to save this scope.
⚠️ Repeat the steps above for another scope named JWT.ReadWrite
Select the Manifest blade on the left.
Set accessTokenAcceptedVersion property to 2.
Select on Save.
Publish Application Permissions
1. All APIs should publish a minimum of one App role for applications, also called Application Permission, for the client apps to obtain an access token as themselves, i.e. when they are not signing-in a user. Application permissions are the type of permissions that APIs should publish when they want to enable client applications to successfully authenticate as themselves and not need to sign-in users. To publish an application permission, follow these steps:
2. Still on the same app registration, select the App roles blade to the left.
3. Select Create app role:
1. For Display name, enter a suitable name : JWT.Read.All.
2. For Allowed member types, choose Application to ensure other applications can be granted this permission.
3. For Value, enter JWT.Read.All.
4. For Description, enter : Allows the app to read the signed-in user's JWT data.
5. Select Apply to save your changes.
6. ⚠️ Repeat the steps above for another app permission named JWT.ReadWrite.All
Configure Optional Claims
1. Still on the same app registration, select the Token configuration blade to the left.
2. Select Add optional claim:
1. Select optional claim type, then choose Access.
2. Select the optional claim idtyp. (Indicates token type. This claim is the most accurate way for an API to determine if a token is an app token or an app+user token. This is not issued in tokens issued to users.)
3. Select Add to save your changes.
Register the client app (web-msal-spa)
1. Navigate to the Azure portal and select the Microsoft Entra ID service.
2. Select the App Registrations blade on the left, then select New registration.
3. In the Register an application page that appears, enter your application's registration information:
1. In the Name section, enter a meaningful application name: web-msal-spa
2. Under Supported account types, select Accounts in this organizational directory only
3. Select Register to create the application.
4. In the app's registration screen, select the Authentication blade to the left.
5. If you don't have a platform added, select Add a platform and select the Single-page application option.
1. In the Redirect URI section enter the following redirect URI (This is a temporary development URI
http://localhost:3000
2. Select Configure
3. Click Add URI and update list with additional bellow URIs (The list will need to be updated with FQDNs where you will run SPA too):
http://localhost:3000/redirect
https://oauth.pstmn.io/v1/callback
4. Select Save to save your changes.
6. Since this app signs-in users, we will now proceed to select delegated permissions, which is is required by apps signing-in users.
1. In the app's registration screen, select the API permissions blade in the left to open the page where we add access to the APIs that your application needs:
2. Select the Add a permission button and then:
3. Ensure that the Microsoft APIs tab is selected.
4. In the Commonly used Microsoft APIs section, select Microsoft Graph
5. In the Delegated permissions section, select openid, offline_access in the list. Use the search box if necessary.
6. Select the Add permissions button at the bottom.
7. Select the Add a permission button and then:
8. Ensure that the APIs my organization uses tab is selected.
9. In the list of APIs, select the API web-msal-api
10. In the Delegated permissions section, select JWT.Read, JWT.ReadWrite in the list. Use the search box if necessary.
11. Select the Add permissions button at the bottom.
7. At this stage, the permissions are assigned correctly. To avoid consent prompts for users or access promts, let the tenant administrator consent on behalf of all users in the tenant for API permissions. Select the Grant admin consent for {tenant} button, and then select Yes when you are asked if you want to grant consent for the requested permissions for all accounts in the tenant. You need to be a tenant admin to be able to carry out this operation.
Postman OIDC Flows Testing
You can test the OIDC Flows using the "Postman" application. You can set Authorization on the "Postman" collection or Rest API.
The following configuration needs to be used:
Type: Oauth 2.0
Add auth data to: Request Headers
Token: OIDC
Header Prefix: Bearer
Auth URL: https://login.microsoftonline.com/{YourAzureEntraTenantID}/oauth2/v2.0/authorize
Access Token URL: https://login.microsoftonline.com/{YourAzureEntraTenantID}/oauth2/v2.0/token
Client ID: {ClientID-web-msal-spa}
Code Challenge Method: SHA-256
Scope: api://{ClientID-web-msal-api}/JWT.Read api://{ClientID-web-msal-api}/JWT.ReadWrite
Client Authentication: Send client credentials in body
Refresh Token URL: https://login.microsoftonline.com/{YourAzureEntraTenantID}/oauth2/v2.0/token
Token Request: Key=Origin Value=http://localhost:3000/ Sendin = Request Headers
Refresh Request: Key=Origin Value=http://localhost:3000/ Sendin = Request Headers
Get Access Token
After clicking Get New Access Token, you should see the success message "Authentication completed" and click the process button. (Make sure your browser is not blocking pop-ups). You will see a valid Access token, which you can use to access the WEB API backend protected with the web-msal-api application.
Decode Access Token
Using the JSON Web Tokens decoder, you can decode base64 access token data. If successful, you should see the audience (AUD) is web-meal-API ClientID information and scopes (SCP) configured as part of the app's configuration.