I Authorize users via EntraId in a Frontend, with React. This works good, but now i want to send the accessToken via Authorization Header to the Backend, this also works. Now the Backend needs to check the Token, there it is starting to get complicated. First of all i get a error 401 (Unauthorized) with "WWW-Authenticate"-Header (Responseheader)
WWW-Authenticate: Bearer error="invalid_token", error_description="The signature is invalid
.
the Backend then shows this error:
info: Microsoft.IdentityModel.LoggingExtensions.IdentityLoggerAdapter[0]
IDX10243: Reading issuer signing keys from validation parameters.
info: Microsoft.IdentityModel.LoggingExtensions.IdentityLoggerAdapter[0]
IDX10265: Reading issuer signing keys from configuration.
info: Microsoft.IdentityModel.LoggingExtensions.IdentityLoggerAdapter[0]
IDX10243: Reading issuer signing keys from validation parameters.
fail: Microsoft.IdentityModel.LoggingExtensions.IdentityLoggerAdapter[0]
IDX10511: Signature validation failed. Keys tried: 'Microsoft.IdentityModel.Tokens.X509SecurityKey, KeyId: '3PaK4EfyBNQu3CtjYsa3YmhQ5E0', InternalId: '3PaK4EfyBNQu3CtjYsa3YmhQ5E0'. , KeyId: 3PaK4EfyBNQu3CtjYsa3YmhQ5E0
'.
Number of keys in TokenValidationParameters: '0'.
Number of keys in Configuration: '8'.
Matched key was in 'Configuration'.
kid: '3PaK4EfyBNQu3CtjYsa3YmhQ5E0'.
Exceptions caught:
'[PII of type 'System.String' is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'.
token: '[PII of type 'Microsoft.IdentityModel.JsonWebTokens.JsonWebToken' is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'. See https://aka.ms/IDX10511 for details.
I already tried to change the configurations:
/*builder.Services.AddMicrosoftIdentityWebApiAuthentication(builder.Configuration);*/
/*builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(builder.Configuration, "AzureAd");
*/
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi()
.AddInMemoryTokenCaches();
/*builder.Services.AddAuthorization(config =>
{
config.AddPolicy("AuthZPolicy", policyBuilder =>
policyBuilder.Requirements.Add(new ScopeAuthorizationRequirement() { RequiredScopesConfigurationKey = $"AzureAd:Scopes" }));
});*/
the uncommented are also tries, which didn't work.
The accessToken is send with axios:
axios.interceptors.request.use(async config => {
const authToken = await instance.acquireTokenSilent({
scopes: ['openid', 'profile', 'email']
});
console.log(authToken.accessToken);
const accessToken = authToken.accessToken;
config.headers.Authorization = `Bearer ${accessToken}`;
return config;
});
I have literally tried everything possible but the error stays.
I trust your codes for authentication and generating access token are correct as you were already able to generate the acccess token. And the configuration in backend API also looks good. Your issue are related to the scopes you used.
Here's the tutorial for protecting our own web api using Azure AD. Just like what you can see in the Expose delegated permissions (scopes)/Expose application permissions (app roles) section, it's required to create a custom api permission and then we could use api://client_id_exposing_api/permision_name
as the scope in our codes. By the way, you can only create one Azure AD application to finish all the tasks(exponse API, grant API permission, create client secret/certificate, and use them both in the React frontend and .Net core web api backend). Here's some samples.
And we can use VS2022 to create a new .net core web api and choose Microsoft Identity Platform as the Authentication Type to get a prepared API project which is already secured by Azure AD. Just change the configuartion in appsetting.json and it shall be simialr to:
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"ClientId": "clientid_which_have_api_permission",
"Domain": "tenantname.onmicrosoft.com",
"TenantId": "common",
"Audience": "api://clientid_of_the_app_exposed_api"
}
And in Program.cs, you only need to have below codes. EnableTokenAcquisitionToCallDownstreamApi().AddInMemoryTokenCaches();
is used for ITokenAcquisition
to generate access token, but not for validate authorization.
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(builder.Configuration, "AzureAd");