1
votes

I am migrating an API of mine from .Net Core 3.1 to .Net 5 which involves updating its authentication. I am using Azure AD to authenticate my users. I can get a token from MSAL in my client-side React-application but cannot authorize to the backend, which responds with:

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

My frontend configuration looks like this:

const pca = new PublicClientApplication({
    auth: {
        clientId: process.env.REACT_APP_AZURE_CLIENT,
        authority: `https://login.microsoftonline.com/${process.env.REACT_APP_AZURE_TENANT}/`,
        redirectUri: window.location.origin,
    },
    cache: {
        cacheLocation: 'sessionStorage',
        storeAuthStateInCookie: false,
    },
});

My backend is not any different from what the Microsoft docs told me to use, in Startup.cs:

services.AddMicrosoftIdentityWebApiAuthentication(_configuration, "AzureAd");

I also tried:

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer(options =>
        {
            options.Authority = $"https://login.microsoftonline.com/{_configuration["AzureAd:TenantId"]}/v2.0";
            options.Audience = _configuration["AzureAd:ClientId"];
        });

When I look at my old tokens (which worked pretty much the same way), I could see that these fields were different (thank you jwt.io)

New:

"aud": "00000003-0000-0000-c000-000000000000",
"iss": "https://sts.windows.net/my-tenant-id/"

Old:

"aud": "my-client-id",
"iss": "https://sts.windows.net/my-tenant-id/"

So is it something with the audience part that makes the new way use the default Microsoft-audience?

TL;DR;

I can log in to Azure AD using my frontend code but cannot use the token provided to call my backend, what the hell am I doing wrong?

1

1 Answers

1
votes

Well, the answer was a very simple one. All I had to do was use:

// Startup.cs
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer(options =>
        {
            const string prefix = "MyConfigPrefix";
            options.Authority = $"{_config[$"{prefix}:Instance"]}{_config[$"{prefix}:TenantId"]}/";
            options.Audience = _config[$"{prefix}:ClientId"];
        });

...

// adal.js

// In my token-request
const tokenRequest = { scopes: [`${process.env.REACT_APP_AZURE_CLIENT}/.default`] };

This gave me the correct audience when requesting a token, and validation in my backend. So, for anyone else stuck here, use correct scopes when requesting a token.

More specifically:

DO THIS WHEN REQUESTING A TOKEN:

const token = await pca.acquireTokenSilent({ scopes: [`${process.env.REACT_APP_AZURE_CLIENT}/.default`] });