Reputation: 119
We have one app that is using MSAL and generating a token with Azure AD. We need that app to call another API and we're passing the current token. That all is good. We have two different apps and I'll include some code to show how the audience (other client id) is able to authenticate
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(opt =>
{
opt.Audience = Configuration["AzureAd:ResourceId"];
opt.Authority = $"{Configuration["AzureAd:Instance"]}/{Configuration["AzureAd:TenantId"]}";
opt.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
{
ValidAudiences = new string[] { "e8zzz-3304-43e0-aaaa-zzzzzzzzz" }
};
});
So authentication isn't a problem. We are using the GraphServiceClient to access the graph api, but the token that we get from the Authorization header is the token passed from the other app and has a client id tied to the other app. It all runs fine until it gets to the line with AcquireTokenAsync and the issue being returned states "Assertion audience does not match the Client app presenting the assertion. The audience in the assertion was '{other app id}' and the expected audience is '{app id of the api}' or one of the Application Uris of this application with App ID '{app id of the api}'(API APP). The downstream client must request a token for the expected audience (the application that made the OBO request) and this application should use that token as the assertion."
public async Task<GraphServiceClient> GetAuthenticatedClient()
{
var httpContext = this.httpContextAccessor.HttpContext;
if (httpContext != null)
{
StringValues authorizationToken;
httpContext.Request.Headers.TryGetValue("Authorization", out authorizationToken);
var authHeader = authorizationToken.FirstOrDefault();
if (authHeader != null && authHeader.StartsWith("bearer", StringComparison.OrdinalIgnoreCase))
{
var token = authHeader.Substring("Bearer ".Length).Trim();
var clientCredential = new ClientCredential(_authOptions.ClientId, _authOptions.ClientSecret);
var authenticationContext = new AuthenticationContext($"https://login.microsoftonline.com/{_authOptions.TenantId}");
var authenticationResult = await authenticationContext.AcquireTokenAsync("https://graph.microsoft.com", clientCredential, new UserAssertion(token));
var delegateAuthProvider = new DelegateAuthenticationProvider((requestMessage) =>
{
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", authenticationResult.AccessToken);
return Task.FromResult(0);
});
return new GraphServiceClient(delegateAuthProvider);
}
}
throw new UnauthorizedAccessException("Invalid User token.");
}
The other point is that I have limited access to Azure AD beyond readonly. Another group controls that. It's kind of political so I am unable to update things to try things on my own and any changes take at least a day turnaround.
I also did set knownApplications in the manifest for the api.
I probably "could" have it use the client credentials from the other app just to see it work, but that's not a really good answer as we don't want to know those creds for other apps.. Surely, this is being done and I'm missing something obvious. Thanks so much ahead of time.. I hope, if anything, this is of use to someone else down the road.
Upvotes: 1
Views: 1869
Reputation: 645
Can you please try passing the token from App to API in the Postman and see if fetches the right App ID.
You can also try this sample for Calling a web API in a web app using Azure AD and OpenID Connect.
Upvotes: -1