[Bug] Unable to get access token for multiple scopes
See original GitHub issueWhich Version of MSAL are you using ? MSAL 4.3.1
Platform .NET Core 2.2
What authentication flow has the issue?
- Desktop / Mobile
- Interactive
- Integrated Windows Auth
- Username Password
- Device code flow (browserless)
- Web App
- Authorization code
- OBO
- Web API
- OBO
Other? - please describe;
Is this a new or existing app? This is a new app or experiment that I’m doing by modifying the following sample project. https://github.com/Azure-Samples/active-directory-dotnet-native-aspnetcore-v2/tree/master/2. Web API now calls Microsoft Graph
I would like to get access token OBO for Graph API and Dynamics CRM API by providing scopes together and getting access token back with multiple audiences, so that it can be used for both of them.
Repro
- Add API Permission on TodoListService-v2 for Dynamics CRM user_impersonation
- Make sure that it also has Microsoft Graph User.Read
- In TodoListController in TodoListService project, add Dynamics CRM user_impersonation scope to line 90: string[] scopes = { “https://graph.microsoft.com//User.Read”, “https://admin.services.crm.dynamics.com/user_impersonation” };
public async Task<string> CallGraphApiOnBehalfOfUser()
{
string[] scopes = { "https://graph.microsoft.com/User.Read", "https://admin.services.crm.dynamics.com/user_impersonation" };
// we use MSAL.NET to get a token to call the API On Behalf Of the current user
try
{
string accessToken = await _tokenAcquisition.GetAccessTokenOnBehalfOfUserAsync(scopes);
dynamic me = await CallGraphApiOnBehalfOfUser(accessToken);
return me.userPrincipalName;
}
catch (MsalUiRequiredException ex)
{
_tokenAcquisition.ReplyForbiddenWithWwwAuthenticateHeader(scopes, ex);
return string.Empty;
}
}
Expected behavior Access token should be returned with multiple audiences.
Actual behavior Access token returned is only for audience for which the scope is mentioned first in the scopes array.
Possible Solution
Additional context/ Logs / Screenshots I’ve tried many combinations but none of them work: “user.read” “user_impersonation” “user.read user_impersonation” “https://graph.microsoft.com//User.Read”, “https://admin.services.crm.dynamics.com//user_impersonation” Tried double forward slashes, single slashes, nothing worked.
I’ve also tried with Postman and it has the same behavior, in that it returns the access token with audience only for the scope that is mentioned first.
Issue Analytics
- State:
- Created 4 years ago
- Comments:7 (4 by maintainers)
Thanks for the link!
In general, multiple audience scenarios are a security risk, which is why we don’t currently expose a way of building it. The main concern here, that Ping leaves out, is that you must trust that every API and micro service receiving a multi audience will never be compromised. If they’re compromised and get a token that can be used to call another audience, they can - and now your data is at risk, and possibly your business if the token has write permissions.
We are working to propose an update to the JWT standards to build tokens that can safely be issued with multiple audiences - but that adds complexity on the client side.
At this time, the secure (and only) option is to get multiple tokens for multiple audiences. This is handled by the libraries including refreshing and caching.
@mohsinonxrm : this is not a limitation of MSAL, but of Azure AD. But I’ll inquire if there are plans to change that. The best practice is to get the tokens with the right scopes just before calling the API.