2

We have a simple setup. Frontend web application gets a token from Azure AD. Frontend uses that token to authenticate requests to our backend .NET Core Web API. Both will be deployed as Azure Web Apps.

We have found a number of resources on this subject (Microsoft Docs, Blogs, Youtube) however, no matter what we try we are getting 401 Unauthorized errors when we send a request from the frontend to the backend.

Here is our setup:

  1. We have 2 app registrations (one for the frontend, one for the backend)

  2. In the Azure Portal I navigated to Azure AD -> App Registrations -> Backend App -> Expose an API -> Add Scope -> Filled out Form: enter image description here

  3. Then navigate to the Frontend app registration -> API Permissions -> Add a permission -> Add Access to API exposed in step 2. enter image description here

  4. Then select "Grant Admin Consent"

  5. Onto the Frontend code:

  6. On the Frontend we are using Microsoft's MSAL library. We have it configured as such:

// Frontend msal config
   {
        msalConfig: {
        auth: {
            clientId: "{frontend clientId}",
            authority: "https://login.microsoftonline.com/{tenantId}/",
            redirectUri: appUri,
            postLogoutRedirectUri: appUri,
            mainWindowRedirectUri: appUri
        },
        cache: {
            cacheLocation: 'localStorage'
        }
    }
  1. We send a login request:
// login.js
        const request = {
            scopes: [
                "User.Read", 
                "api://{Backend Application Id From AzureAD App Registration}/access_as_user"
            ]
        };
        instance.loginPopup(request).catch(
            (error) => {
                console.log(error);
            }
        );

  1. This works as expected and users are able to login and out of our frontend application.
  2. We place our Azure AD provided token in our Authorization header in requests to our backend API (always returns a 401).
  3. Backend code using Microsoft.Identity.Web (.NET 5):
// .Net appsettings.json  
 "AzureAd": {
   "Instance": "https://login.microsoftonline.com/",
   "ClientId": "{backend clientId}",
   "TenantId": "{tenantId}"
 }
// Startup.cs

using Microsoft.Identity.Web;

ConfigureServices(IServiceCollection services)
{
 //other services
 services.AddMicrosoftIdentityWebApiAuthentication(Configuration, "AzureAd");
 //other services
}

Configure(IApplicationBuilder app, IWebHostEnvironment env)
{ 
 // other config
 app.UseRouting();
 app.UseAuthentication();
 app.UseAuthorization();
 // other config
}

Any help on how to proceed would be greatly appreciated. We are testing locally right now, but once we get auth working we will be deploying the frontend & backend applications to Azure Web Apps.

UPDATE:

I can see in the 401 response headers that I am getting:

Bearer error="invalid_token", error_description="The signature is invalid"

9
  • Are your API endpoints protected with the Authorize attribute? If so, how are you authenticating the user? Commented Feb 3, 2022 at 22:23
  • I have placed the [Authorize] attribute on my controller yes. Users are authenticating on the client side with Azure AD, then sending their tokens to my backend api which is returning nothing but 401 errors Commented Feb 3, 2022 at 23:06
  • Did you try to decode your token and compare scope and audience parameters? Does scope(or scp) have value access_as_user? Does audience (or aud) contain backend client id? It could be that token (provided to backend) is actually for Microsoft Graph. Commented Feb 3, 2022 at 23:18
  • @Serhii The token I am getting on the frontend and sending to the backend does not appear to have either in the token payload. "scp": "openid profile User.Read email" ... "aud": "00000003-0000-0000-c000-000000000000" Commented Feb 3, 2022 at 23:25
  • 1
    You are using a token for Microsoft Graph (check appId here: shawntabrizi.com/aad/…). The frontend has received a token for MS Graph and sent it to the backend Commented Feb 3, 2022 at 23:28

1 Answer 1

3
  1. Try to add "Audience" parameter into AzureAD section: "Audience": "api://{Client_Id}".

  2. To receive more info about auth you can pass subscribeToJwtBearerMiddlewareDiagnosticsEvents: true into services.AddMicrosoftIdentityWebApiAuthentication and check your logs after unsuccessful request.

  3. Also, you can decode(https://jwt.io) your token and check the payload section if there are required scope and audience.

  4. It could be that token (provided to backend) is actually for Microsoft Graph(check appId here: shawntabrizi.com/aad/…). If "scp" is "openid profile User.Read email" and "aud" is "00000003-0000-0000-c000-000000000000" then you are using the wrong token for your backend. Ask Frontend to check the way how they are receiving a token.

Frontend guy put something like this into code, correct me if I am wrong:

 
 public static msalInterceptorConfigFactory(): MsalInterceptorConfiguration {
    const resourceMap = new Map<string, Array<string>>();
    resourceMap.set(environment.apiUrl, [environment.scope]);

    return {
      interactionType: InteractionType.Redirect,
      resourceMap
    };
  }

  public static msalGuardConfigFactory(): MsalGuardConfiguration {
    return {
      interactionType: InteractionType.Redirect,
      authRequest: {
        scopes: [environment.scope]
      }
    };
  }

# module.ts
 providers: [
...
    {
      provide: MSAL_GUARD_CONFIG,
      useFactory: msalGuardConfigFactory
    },
    {
      provide: MSAL_INTERCEPTOR_CONFIG,
      useFactory: msalInterceptorConfigFactory
    },
...
  ],

Sign up to request clarification or add additional context in comments.

3 Comments

Hi @Serhii I have replicated this in my project and I get the error is invalid audience when the aud claim is It is the one that I copied and pasted from the azure portal and scp claim the same too
Hi @kintela, what configuration you are using for backend side?
Hi @Serhii is shown in my post

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.