I have a Blazor WASM client application that is trying calling an aspnet web api. From the web API, I am trying to use the Microsoft Graph SDK with delegated permissions.
On the server, when I retrieve an instance of GraphServiceClient
through dependency injection, I get the following error when trying to read user data.
var me = await graph.Me.Request().GetAsync();
StatusCode: 400
ResponseBody: {
"error":"invalid_grant",
"error_description":"AADSTS70000: The request was denied because one or more scopes requested are unauthorized or expired. The user must first sign in and grant the client application access to the requested scope.",
"error_codes":[70000],
"error_uri":"https://login.microsoftonline.com/error?code=70000",
"suberror":"consent_required",
(some data omitted)
}
However, if I obtain a token manually with ITokenAcquisition
, everything works correctly.
var token = await tokenAcquisition.GetAccessTokenForUserAsync(new string[] { "User.Read" });
GraphServiceClient graph = new GraphServiceClient(new DelegateAuthenticationProvider(request =>
{
request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
return Task.CompletedTask;
}));
var me = await graph.Me.Request().GetAsync();
I was under the impression that the injected GraphServiceClient would obtain tokens using the ITokenAcquisition and passing the scopes specified in Startup.
Am I configuring something wrong? It seems that the token used in the injected client doesn;t contain the proper scopes.
I have tried fully logging out of my Microsoft account, and deleting the browser cache. I have consented to all of the necessary permissions.
My api server startup looks like this.
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi()
.AddMicrosoftGraph(builder.Configuration.GetSection("GraphAPI"))
.AddInMemoryTokenCaches();
server appsettings.json
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"TenantId": "consumers",
"ClientId": "{clientId}",
"ClientSecret": "{clientSecret}",
"Scopes": "AccessAsUser",
"CallbackPath": "/signin-oidc"
},
"GraphAPI": {
"BaseUrl": "https://graph.microsoft.com/v1.0",
"Scopes": "User.Read"
},
Client startup
builder.Services.AddMsalAuthentication(options =>
{
builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication);
options.ProviderOptions.LoginMode = "redirect";
options.ProviderOptions.DefaultAccessTokenScopes.Add("api://{clientId}/.default");
options.ProviderOptions.DefaultAccessTokenScopes.Add("profile");
options.ProviderOptions.DefaultAccessTokenScopes.Add("offline_access");
});
client appsettings.json
"AzureAd": {
"Authority": "https://login.microsoftonline.com/consumers",
"ClientId": "{clientId}",
"ValidateAuthority": true
}