title: Calling an Azure AD secured Azure Function from React SPA/Azure Static Web App
body: <p>I'm developing an SPA with React that is hosted as an Azure Static Web App. The App is secured with Azure AD Authentication which works great, I already built a Login that works fine and I can call Azure (Graph) APIs with the token I got and retrieve information for the granted scopes (e.g. user profile picture). To achieve this, I'm using a wrapper called <a href="https://github.com/syncweek-react-aad/react-aad" rel="nofollow noreferrer">React AAD MSAL</a> which neatly wraps the Microsoft Authentication Library (msal@1.4.0).</p>
  <p>So far so good, no problems here. But I'm in need of a backend, of course. I decided to this with Azure Functions, since serverless is the best way for me here. So I made a quick HTTP trigger protoype that runs in Azure as Azure Function und works when I call the URL with the correct paramters.</p>
  <p>But of course the Azure Function needs to be secured, so only my React App can call this function. So I thought there should be way to do this through Azure AD, since my user is already logged in as such.</p>
  <p>I tried and tried and tried different ways I found online but none of them seem to work or I am doing something wrong.</p>
  <p>The general tutorial I tried to follow is <a href="https://docs.microsoft.com/en-us/azure/app-service/configure-authentication-provider-aad#advanced" rel="nofollow noreferrer">this one</a> from MS itself. I tried using the &quot;Express&quot; setting which of course didn't work. I tried the advanced configuration, which also didn't work. The advanced tutorial says you need to have an App registration for the service, I'm not even sure if this is can be my Static Web App or a new on (I tried both with no success). Isn't it enough to tell the Azure Function that it is now AAD secured and may only accept calls from a source secured by an access token that contains the App ID of my app, which is provided in the settings? You can easily provide all these settings, it just doesn't seem to work.</p>
  <p>So I'm stalling very early on here. To call the function itself, I first need to get a Authorization Token. According to <a href="https://docs.microsoft.com/en-us/azure/app-service/app-service-authentication-how-to" rel="nofollow noreferrer">this tutorial from MS</a> (see &quot;Validate tokens from providers&quot;), I need to send an access token which I got when logging in to my SPA Web App to the Azure Function endpoint ending in <code>.auth/login/aad</code>. Getting this token is easy, since React AAD MSAL provides a method <code>authProvider.getAccessToken()</code> which I can use to extract it. I'm then making a POST request to <code>https://&lt;My Azure Function URI&gt;/.auth/login/aad</code> with the access token in the body as JSON <code>{ 'access_token': authToken.accessToken }</code>. I should be getting an Authentication Token which I can then use to call the actual function, but I always get the same response, no matter what I try: <code>You do not have permission to view this directory or page.</code></p>
  <p>So this is where I am. I tried different methods and solutions I found to no avail. Maybe I did something wrong from the ground up, maybe I'm using the wrong methods, I really don't know at this point. Does anyone have experience with this? Is there something wrong in my general approach, do I need to do something else? Or is it just something in the configuration I need to change?</p>
  <h2>Edit</h2>
  <p>Since it was asked, here's how I retrieve the token. The concept behind this is using a <code>redux-thunk</code> to dispatch an asynchronous action to the react-redux store. I simplified it not only for this question here but for my testing as well. Right now I'm only trying to get the authentication token and log the answer the POST request is giving me:</p>
  <pre><code>import { authProvider } from '../../Authentication/AuthProvider';
  
  //Fetch
  async function getAccessToken(authToken) {
    const body = { 'access_token': authToken.accessToken };
  
    fetch('https://&lt;My Azure function URL&gt;/.auth/login/aad', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(body)
      },
    ).then(response =&gt; {
      console.log(response);
    });
  }
  
  export const fetchAddressData = () =&gt; async dispatch =&gt; {
    const token = await authProvider.getAccessToken();
    await getAccessToken(token);
    // The actual call to the Azure function will go here once we have an Authentication Token
  }
  </code></pre>
  <p>The <code>authProvider</code> is a component from <code>react-aad msal</code> and the configuration looks like this:</p>
  <pre><code>import { MsalAuthProvider, LoginType } from 'react-aad-msal';
  
  //MSAL Config
  const config = {
    auth: {
      authority: '&lt;Tenant ID&gt;',
      clientId: '&lt;Client ID from App registration (Azure Static Web App)&gt;',
      redirectUri: window.location.origin
    },
    cache: {
      cacheLocation: &quot;localStorage&quot;,
      storeAuthStateInCookie: true
    }
  };
  
  // Authentication Parameters
  const authenticationParameters = {
    scopes: [
     'openid',
     'user.read', 
     'https://&lt;Azure Function URI&gt;/user_impersonation'
    ],
    forceRefresh: true
  }
  
  // Options
  const options = {
    loginType: LoginType.Redirect,
    tokenRefreshUri: window.location.origin
  }
  
  export const authProvider = new MsalAuthProvider(config, authenticationParameters, options)
  </code></pre>
  <h2>Edit 2</h2>
  <p>I tweaked some additional settings trying to work with the user impersonation, still no success. Here's an overview over my current Azure settings that are important for this (did I forget any?).</p>
  <p>Azure Function:</p>
  <p>Authentication is activated, AAD auth only, advanced settings:
  <a href="https://i.stack.imgur.com/YPpkq.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/YPpkq.png" alt="enter image description here" /></a></p>
  <p>Azure Function - App Registration:</p>
  <p>Authentication settings:
  <a href="https://i.stack.imgur.com/oK5Jj.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/oK5Jj.png" alt="enter image description here" /></a></p>
  <p>Client secret:
  <a href="https://i.stack.imgur.com/ZedxR.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/ZedxR.png" alt="enter image description here" /></a></p>
  <p>Expose an API - Exposing user_impersonation API so the Web App can consume it:
  <a href="https://i.stack.imgur.com/jImqx.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/jImqx.png" alt="enter image description here" /></a></p>
  <p>Azure Static Web App (React SPA) - App Registration:</p>
  <p>Application URI ID which is used as Token Audience in the Azure Function (advanced authentication setting):
  <a href="https://i.stack.imgur.com/xyeXx.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/xyeXx.png" alt="enter image description here" /></a></p>
  <p>API permissions - using the user_impersonation API which is exposed by the Azure Function App Registration:</p>
  <p><a href="https://i.stack.imgur.com/xU3rj.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/xU3rj.png" alt="enter image description here" /></a></p>
  <p>Is there anything wrong in this configuration? It mostly likely is, but I don't know what since I followed the tutorial on MSDN. I only added the user_impersonation afterwards since it didn't work.</p>