I am currently building a web app using Asp.net core web API as backend and Vue as frontend. THe authentication is realized through msal. I can successfully authenticate within the frontend but when I try to send an HTTP request against the asp.net web api to a protected endpoint, I get a 401 response even tho the JWT is contained in the request header. As I'm pretty new to the authentication world, I'm hoping for any help here.
appsettings.json in backend
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"TenantId": "<my-tenant-id>",
"ClientId": "<my-client-id>",
"Audience": "api://<app id>"
}
authConfig.ts in frontend
import { LogLevel, PublicClientApplication } from '@azure/msal-browser';
export const msalConfig = {
auth: {
clientId: '<my-client-id>',
authority: 'https://login.microsoftonline.com/<my-tenant-id>'
},
cache: {
cacheLocation: 'localStorage'
},
system: {
loggerOptions: {
loggerCallback: (level: LogLevel, message: string, containsPii: boolean) => {
if (containsPii) {
return;
}
switch (level) {
case LogLevel.Error:
console.error(message);
return;
case LogLevel.Info:
console.info(message);
return;
case LogLevel.Verbose:
console.debug(message);
return;
case LogLevel.Warning:
console.warn(message);
return;
default:
return;
}
},
logLevel: LogLevel.Verbose
}
}
};
export const msalInstance = new PublicClientApplication(msalConfig);
export const loginRequest = {
scopes: ['api://<app id>/full']
};
export const graphConfig = {
graphMeEndpoint: 'https://graph.microsoft.com/v1.0/me'
};
axios.ts in frontend
import axios from 'axios';
import { msalInstance, loginRequest, graphConfig } from './authConfig';
const apiClient = axios.create({
baseURL: 'https://localhost:7158'
});
apiClient.interceptors.request.use(async (config) => {
const activeAccount = msalInstance.getActiveAccount();
const accounts = msalInstance.getAllAccounts();
if (!activeAccount && accounts.length === 0) {
return config;
}
try {
const token = await msalInstance.acquireTokenSilent({
...loginRequest,
account: activeAccount || accounts[0]
});
config.headers.Authorization = `Bearer ${token.idToken}`;
} catch (error) {
console.error();
}
return config;
});
export { apiClient };
The response I get has the following error: "Bearer error="invalid_token", error_description="The audience '' is invalid""
The error_description is only present when specifying the audience uri in the appsettings.json in backend. When I do not specify it, only the error but not the error_description is present.
I tried debugging and checked if the jwt was really valid using jwt.io until I came accross that I have to add the audience to the appsettings.json in the backend.
I generated access token using below parameters via Postman:
https://login.microsoftonline.com/TenantID/oauth2/v2.0/token
client_id:ClientID
grant_type:authorization_code
scope:api://ClientID/test.read
code:code
redirect_uri:https://jwt.ms
client_secret:ClientSecret
When I decoded the access token, the aud is ClientID
:
Now, I tried to call the graphMeEndpoint
using the above generated access token and got the similar error:
GET https://graph.microsoft.com/v1.0/me
The error "The audience is invalid" usually occurs if you are access token audience is not matching the API you are calling.
In your scenario, the error occurred as you are generating access token for web API and calling Microsoft Graph API.
To resolve the error, Add Microsoft Graph API permissions in the Azure AD Application:
Generate the access token by passing scope as https://graph.microsoft.com/.default
When I decoded the access token, the aud is https://graph.microsoft.com
:
I am able to call the graphMeEndpoint
successfully:
GET https://graph.microsoft.com/v1.0/me
In your case, to resolve the error modify the code like below:
appsettings.json
file
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"TenantId": "<my-tenant-id>",
"ClientId": "<my-client-id>",
"Audience": "https://graph.microsoft.com"
}
authConfig.ts
file
export const msalInstance = new PublicClientApplication(msalConfig);
export const loginRequest = {
scopes: ['user.read']
};
export const graphConfig = {
graphMeEndpoint: 'https://graph.microsoft.com/v1.0/me'
};
If you want to call the Microsoft Graph API, then change the aud
to Graph. If you want to call the Web API, then no need of changing the aud
to Graph API.