Overview
This is an upgrade of this great post from Janne Hansen. Thanks to him. He helped me alot!The goal is to autenticate a user with Azure AD on a Single Page Application made with JavaScript, and, from this page, let the user call an Azure API protected with Azure AD while the user has no need to sign in for the API. There is also a notion of Single Sign On (SSO) in there. At the first sign-in user authenticates with Azure AD, then, is also authenticated for the API
The code of Jane Hansen is available at GitHub:jannehansen/SinglePageAndAAD
It uses MSAL browser V2, and stil works perferctly well.
I had to update Janne Hansen's post rather for the steps of Azure cofiguration.
Authentication Flow - First step
First, to well configure everything for the solution in Azure Portal and understand the code used for MSAL (either JavaScript or Angular) you need to figure out how the double authentication flow is working.For authenticating a user to Azure AD, you have to use Azure AD Applications. Azure AD applications are like super heroes that receives from a user a demand to be authenticated and let the user pass through Azure AD. But as every super heroes their powers are limited. They can act only for a certain scope: after being authenticated, you can be redirected only for the demanded scope, SPA, API, MS online product, SharePoint online, Outlook online etc...
So, for our solution, first we need two super heroes:
- one application for the scope of our Single Page Application
Testing this first step
Clone with git or dwonload the code GitHub:jannehansen/SinglePageAndAAD Install NPM http-serverRun a command, navigate to the code repository to the folder functioncall and serve the SPA locally by:
- running http-server
- calling http://localhost:8080 in a browser
Configuring the portal for the SPA
We are now going to create our first superhero for the SPA authentication.In Azure Portal, go to Azure Directory. Then, in the left menu, click on "App Registrations", then, click to New Registration: Then fill the required fields:
- The App name
- Choose SPA as a platform
- and http://localhost:8080 as the redirect url
By the way, you will see the App name and you will be sure you were calling the good App. Finally you get signed in and the SPA displays your AAD account information. Important: It is super difficult to get rid of cache with this solution using http-server, thus, use systmatically private/incognito windows while doing your tests.
And yes, I know, you will have to sign in for every test, and you may get nervous.
Configuring the portal for the API
Now, let's do the part dedicated to the API.This time, we are not going to use the Azure Active Directory. We are going to use the configurtaion panes of an existing API within Azure portal.
If you have an API available in your Azure tenant, go to it.
If you haven't, you can use my previous post to quickly build an API based on PowerShell Azure function, then come back to this post.
Go to your API configuration within Azure Portal and click on authentication in the left menu then click on "add identity provider" button then choose Microsof as prodider, and let create new app registration checked.
Type your AAD app name.
Important:It is better to create the API and create the Azure Active Directory App from the API Authentication pane, than create the AAD app first then use it for the API authentification because Azure will configure everything for your API. Let the other choices by default, even redirect is said not be recommended for API, because we are going to use the redirect later.
Then your authentication is set API side in the Azure portal. Now click the name of your AAD app newly created, and you will be redirected to this new app in Azure AD and if you click authentication in the left menu you will see that the redirect link for sign in has been created automatically! Now's the time to test that, so paste your API url in a browser and you will be asked to sign in. then, once signed, you will see the app permission consent pop-up and will be able to check that you called the good AAD app to authentify: and finally, after having consent, you'll see your API display its content in the browser.
Single Sign On cofiguration
You might say, well, that's fine all that, but if, as you say, the superheroes are stuck in their own perimeters, how can I log in with the SPA superhero and then, be authenticated for the API with the other superhero without signing in a second time?
It's elementary, my dear Watson
Go back to the API superhero in AAD and go to Expose API pane. Microsoft has planned this, as you can tell an api what is its client application: Click on the "+"
check the proposed scope and paste the client id of the SPA AAD app Here is the final screenshot before saving
CORS
To access an API from a SPA, this not the only configurations you have to do. You also have to allow the url of the SPA to call the API. This is CORS (Cross-Origin Resource Sharing). Normally an API can only be accessed by an url with the same domain. Here, were are wrong. SPA is http://localhost and API is https://helloworldfunction1123.azurewebsites.net. So we have to authorize http://localhost to call https://helloworldfunction1123.azurewebsites.net.So, go back to Azure Portal in the API configurtaion, locate CORS in the left menu and enter http://localhost:8080 as an authorized domain for CORS.
JavaScript MSAL code side and testing
Now, everything in Azure is configured properly, we have to replicate this configuration in our MSAL code.You have only 2 params to chang in authRedirect.js The value of the only entry for the scopes table and the url of the API you want to call.
Get the code
So now, after the code modification, stop the http-server with ctrl C. Restart it. Open a new inPrivate/Incognito browser window.
Sign in again to the SPA in if you click the link to the API while signed in: you will have the response of your API displayed:
To get further
You noticed I have displayed the second authorization token in the browser console. You can decrypt it using JWT.io.You will notice we retrieve the authentication origin with the spa client id and the authorization scope for the API.
The token is saying: "I come from the spa and request authentication for the API"