Previously we configured an Azure Active Directory Setup for our API and SPA. Next we will get our SPA Code Sample updated to work with Azure AD.
Running the sample on a Developer PC requires the Original Setup Steps, though of course we do not need to configure Okta since we are using Azure AD instead.
Download code from GitHub via this command. The sample uses SSL URLs for the SPA and API, as required by Azure AD.
- git clone https://github.com/garyarcher36/authguidance.websample.azure
Make sure you also import the below Root Certificate into your Certificate Store, as covered in Developer SSL Setup, to prevent browser warnings:
API and SPA Configuration Changes
We have updated our API to point to the Azure AD Authorization Server. Also, because we are dealing with in memory validation, we must configure an expected audience for access tokens that matches our API’s ‘App ID URI‘.
Our SPA also points to Azure AD, and the other change is a new ‘resource‘ parameter that Azure AD requires us to supply during login redirects:
OIDC Client Id Token Validation
After login, OIDC Client needs to validate the id token issued by Azure AD, and by default OIDC Client will attempt to download token signing keys.
However, this breaks due to Azure AD not allowing the CORS request – and there is a similar problem if the UI calls the User Info endpoint:
This is annoying, but we will work around it by downloading token signing keys using a double hop, via our API:
It turns out also that User Info does not need to be downloaded, since Azure AD adds user name and email fields to the Id Token and OIDC Client can read it from there.
SPA Code Changes
The changes to our Authenticator class are shown below:
- We first make an Ajax call to the API to get Token Signing Keys
- We pass the result into our Authenticator class
- User Info Download is disabled
- An extra ‘resource’ query parameter is passed in from the SPA config
API Code Changes
The main change to our API is that it no longer uses Introspection to validate access tokens and instead uses In Memory Token Validation.
This topic is quite interesting in terms of developer understanding, so I have covered it in a separate post.
If we now run our API with ‘npm run httpDebug‘ and our SPA with ‘npm start‘, we can view key changes to HTTPS messages in an HTTP debugger.
When our SPA loads, and before the login redirect, there is a double hop to download token signing keys. This API request does not need to be secured.
The login redirect now has an extra, vendor specific, query parameter, to identify the API it wants an access token for:
The login uses the Microsoft Login Page and you will log in with your Azure AD Credentials:
On return from login, the Implicit Flow token validation in OIDC Client completes successfully, using the token signing keys we provided.
The SPA then securely calls the API with the Azure AD token. The API strictly validates the access token, then returns data:
Our SPA uses OIDC Client to read Profile and Email information from the Id Token, then displays the User Name of the logged in user:
The features for Token Renewal and Basic Logout also work OK. Therefore we have met all of our usability requirements.
Azure AD Id Token
First let’s look at the Id Token returned to the UI in a JWT Viewer. This token is proof of the authentication event and has the SPA as its audience.
Note that in Azure AD, the token always includes the user’s Azure profile and email information, even if I only specify scope=openid.
Azure Access Token
The Access Token is intended for calling our API, so it has a different audience value. It also contains User Profile and Email information.
User Ids in Tokens
As covered in previous posts, a key capability is for an API is often to extract the User Id and use it to apply business logic.
My Azure AD User Id can be viewed against my User in the Portal, under Azure Active Directory / All Users and is this value:
Azure AD tokens seem to include the Azure User Id in the oid claim as opposed to the sub claim. So APIs will need to use the oid claim to apply personalized authorization and data access.
Token and User Session Lifetimes
My Azure account is a trial one so I am using default times for Access Tokens and User Sessions, which are not too far out of line with our requirements:
- Access Tokens last for 60 minutes
- User Sessions last for 24 hours
Real world companies will use Azure AD B2C and be able to configure Custom Token and Session Lifetimes via the Azure Portal.
Where Are We?
We have got past all blocking issues for our SPA and API, though it was a little more difficult than we’d like.