Okay, so I've spent the last two days with this error, and just found a solution. In my search, I didn't find an single answer solving the issue that I had (rather I found multiple that eventually pointed me to the solution). So here's my attempt at explaining you the solution to the "Access token validation failure. Invalid audience" error:
TLDR:
- Check that "https://graph.microsoft.com" is listed as AUD (audience) in the access token you receive when authenticating with MSAL on https://jwt.ms/ (Microsoft is behind the site jwt.ms source: https://docs.microsoft.com/en-us/azure/active-directory/develop/access-tokens). In my case, the back-end API scope was listed, not "https://graph.microsoft.com". That's why the "audience" was invalid when Microsoft graph api checks the access token.
- The solution is to request two different access tokens, one for the backend scope, and one for the https://graph.microsoft.com/User.Read scope:
/**
* Retrieve token for backend
*/
export const getToken = async (account): Promise<AuthenticationResult> => {
return await msalInstance.acquireTokenSilent({
scopes: [process.env.REACT_APP_API_SCOPE as string],
redirectUri: current_url,
account,
});
};
/**
* Retrieve token for Microsoft Graph API:
*/
export const getTokenForGraphApi = async (
account
): Promise<AuthenticationResult> => {
return await msalInstance.acquireTokenSilent({
scopes: ["https://graph.microsoft.com/User.Read"],
redirectUri: current_url,
account,
});
};
Here's the long story of how I found out:
I wanted to be able to query the Microsoft Graph API from a React application.
I've had the admin of my organization set up the Azure Portal, so that our App registration has API Permissions:
- Backend API permission
- Microsoft Graph
- "User.Read"
- "User.ReadBasic.All".
In React when I authenticate, I've used scopes:
scopes: [
process.env.REACT_APP_API_SCOPE as string,
"User.Read",
],
The authentication goes well, and I get an access token.
The access token works with our backend API, however when I try to use the access token with the Microsoft Graph API, I get the error:
"Access token validation failure. Invalid audience".
I read and searched forums, and I tried using jwt.ms.
Only our API is listed as "aud", and hence I suspect I need a token where both our API and "https://graph.microsoft.com" is placed.
I then tried preceding my User.Read scope with "https://graph.microsoft.com" so it would be:
scopes: [
process.env.REACT_APP_API_SCOPE as string,
"https://graph.microsoft.com/User.Read"
],
But it failed to authenticate with the error message:
"AADSTS28000: Provided value for the input parameter scope is not valid because it contains more than one resource. Scope api://{API-application-id}/a-scope https://graph.microsoft.com/User.Read openid profile is not valid."
Here, our backend is one resource, which has a-scope, and "https://graph.microsoft.com" is another resource with scope "User.Read".
The solution is hence to require two seperate access tokens: One with scope "https://graph.microsoft.com/User.Read", that you can use with the graph api, and another access token for your backend:
/**
* Retrieve token for backend
*/
export const getToken = async (account): Promise<AuthenticationResult> => {
return await msalInstance.acquireTokenSilent({
scopes: [process.env.REACT_APP_API_SCOPE as string],
redirectUri: current_url,
account,
});
};
/**
* Retrieve token for Microsoft Graph API:
*/
export const getTokenForGraphApi = async (
account
): Promise<AuthenticationResult> => {
return await msalInstance.acquireTokenSilent({
scopes: ["https://graph.microsoft.com/User.Read"],
redirectUri: current_url,
account,
});
};