This article shows how to call Azure AD protected Functions from Single Page Application (SPA). Although the task seems trivial, I spent about two days to find working, up-to-date instructions. Implementation after that took about an hour.

Target

In short: I needed to call Azure AD-protected Functions from my Single Page App (SPA).

I used this microsoft msal.js demo app for vanilla javascript example as the base for my experiments. It contains just what we need – SPA which would call external API’s using Azure AD authentication.

At the moment MS would like us to use their MSAL.js library to handle the login and further token retrieval using AADv2 protocol in SPAs.  The example app showed how the lib was used to initiate user AD login, and then call external API. The example worked nicely without issues.

My modifications to the example app was just to change the readEmail() to call my own function. Here’s what my modified example app finally did:

  • User opens up the single page app (SPA) index.html in browser.
  • User clicks “login” on the app page.
  • Login flow is initiated by calling msal.js, which opens a popup window and shows user the Microsoft Azure AD login page.
  • User logs in using the popup window (and maybe gives consent to whatever app needs consent for).
  • In the end, login page sends a cookie to user’s browser containing the login information. msal.js now dismisses the popup window.
  • After login, we want to call Azure Functions, which is protected by Azure AD.
  • Before the Functions call, we again use msal.js to obtain auth token from Azure Ad.
  • Now we can call Azure Function as usual. Only extra step is to add “Authorization”:”Bearer “+token header to call you received from msal-call.
  • Do whatever you like with call Function call results. Alert is always a good option.

401 – forbidden

Problems started when I switched the “readMail()” MS Graph API call to point to my own AAD protected Function app. I only got 401 – Forbidden replies from my Function App. No explanations on the error message.

To shorten the story: The problem was in the App Registrations. The example required only the single page app to be registered to the Azure AD. The key finding was this page: Tutorial – Enable your Web Apps to sign-in users and call APIs with the Microsoft identity platform for developers. This explained all the different patterns used in authentication. Finding the Call your own API – example shows exactly how the app registrations should be done using the “on-behalf-of” pattern. The instructions guide you to create this kind of construct, that works also with single page js apps:

Image: Single Page App, Functions and App registrations.

What is a Scope?

With the two app registrations now most likely done right, the code in the example app contained one more mystery. What is a scope, that was passed along the token retrieval calls? I really don’t know. You just need to pass it with the call to get what you need.

const loginRequest = {
   scopes: ["openid", "profile", "User.Read"]
}

const tokenRequest = {
   scopes: ["Mail.Read"]
};

Code: Scopes in the unmodified example app

These scopes were used in the example app to call login and the Graph API/messages to get user’s emails. What’s the scope I need to put in my Function App calls? If you guess wrong, you’ll get 401 forbidden. The answer: You’ll find your function app Scope from Function App Registration. Keep reading.

Function App Azure AD Login Express setup

When you turn on Azure AD auth for your function app, the express setup process creates you a new app registration to your default Azure AD. You can see the app registration details in portal by selecting “Azure Active Directory” on the left panel, then select App Registrations. You may need to further click on show “All app registrations” for you function app registration to show in the list. Select it to view the details.

The important part in function app (or any API app registration) is that you must Expose an API for others to use. The express setup did this automatically for you, you can already see one “Scope” in list of scopes. Click the scope row to view the details.

 

Expose Api

Scope Name

Image: Expose an Api & Scope Name

The above string is your Scope to put in your spa – code.

If you did the Single Page App Registration according the instructions on this page, you now have everything you need. One more thing to make sure – your SPA code msalConfig needs to point to your Single Page App Registration (client id and potentially tenant id in some cases), not the function app registration. And of course, change the call endpoint from MS Graph API to your function app.

// initialize MSAL
    const msalConfig = {
        auth: {
            clientId: "Enter_your_client_id",
            authority: "https://login.microsoftonline.com/common",
            validateAuthority: true
        },
        cache: {
            cacheLocation: "localStorage",
            storeAuthStateInCookie: false
        }
    };

const funcObjScope = {
    scopes: ["https://anotherv.azurewebsites.net/user_impersonation"]
};

Code: Your MSALConfig points to your Single Page App Registration on Azure AD (not the function app registration). Your function app scope is something like mine – “xxxxx/user_impersonation”.

This is pretty much it. Now you should be able to call your AD-protected functions. As you saw, lots of details has to go right in order to make this work. After finding the right document(s), the implementation usually takes only few minutes.

Links collected

 

This method works now at the time of writing. Please notify me when it doesn’t work anymore.

Until that – Enjoy!