I have created a WebAPI using .NET 5 using Azure AD for authentication of the user. I am using Postman to generate the Access Token and the WebAPI Works when passing Access Token as Bearer.
I want to call Graph API to get the user Calendar & Profile using the Access Token but unable to do so. I have followed few articles mentioned below with no luck.
Invalid Authentication Token error when using the Access Token to call /me Graph API
App registration to use My Org Only. I have added Delegated permissions to Graph API.
Created A custom scope using Expose An API as the WebAPI Was throwing Signature Invalid Error.
My WebAPI Configure Services in StartUp.cs Code:
services.AddMicrosoftIdentityWebApiAuthentication(Configuration);
My AppSettings.json
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "<Domain",
"ClientId": "<ClientId>",
"TenantId": "<TenantId>"
},
I have tried to follow couple of articles which suggest On Behalf Of Flow
https://joonasw.net/view/azure-ad-on-behalf-of-aspnet-core
Struggle with MS Graph and asp.net Core API
I am lost any help is much appreciated.
EDIT1:
I tried Implementing the solution suggested by Farid. The postman output was returning HTML Response to Sign In. It is a ASP.NET Core 5 WebAPI so I changed the ConfigureServices code to below:
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi()
.AddMicrosoftGraph(Configuration.GetSection("DownstreamApi"))
.AddInMemoryTokenCaches();
I receive the following Error.
System.InvalidOperationException: No authenticationScheme was specified, and there was no DefaultChallengeScheme found. The default schemes can be set using either AddAuthentication(string defaultScheme) or AddAuthentication(Action<AuthenticationOptions> configureOptions).
at Microsoft.AspNetCore.Authentication.AuthenticationService.ChallengeAsync(HttpContext context, String scheme, AuthenticationProperties properties)
at Microsoft.AspNetCore.Authorization.Policy.AuthorizationMiddlewareResultHandler.HandleAsync(RequestDelegate next, HttpContext context, AuthorizationPolicy policy, PolicyAuthorizationResult authorizeResult)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
Update:
I was able to resolve the error by using below code:
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddMicrosoftIdentityWebApi(Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi() .AddMicrosoftGraph(Configuration.GetSection("DownstreamApi"))
.AddInMemoryTokenCaches();
I am able to read my profile but not able to obtain Calendar Items. It could be due to Admin Consent Requirement.
As per your given information it seems your token has expired, so firstly try to regenerate that, additionally, you have added Delegated permissions
that's fine but I doubt you haven added the grant admin consent after adding Graph API permission. So its mandatory and please double check that. See the below screen capture. Please follow the below steps to get token and user info using Microsoft Graph API
Grant Admin Consent:
Token Aquisition Example:
Check the appsettings.json
it should be like below:
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "yourdemain.onmicrosoft.com",
"TenantId": "",
"ClientId": "",
"ClientSecret": "",
"ClientCertificates": [
],
"CallbackPath": "/signin-oidc"
},
"DownstreamApi": {
"BaseUrl": "https://graph.microsoft.com/v1.0",
"Scopes": "https://graph.microsoft.com/.default"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
string[] initialScopes = Configuration.GetValue<string>("DownstreamApi:Scopes")?.Split(' ');
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi(initialScopes)
.AddMicrosoftGraph(Configuration.GetSection("DownstreamApi"))
.AddInMemoryTokenCaches();
services.AddControllersWithViews(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
});
services.AddRazorPages()
.AddMicrosoftIdentityUI();
}
Note: You can ignore below two service from the
ConfigureServices
understartup.cs
.EnableTokenAcquisitionToCallDownstreamApi(initialScopes) .AddMicrosoftGraph(Configuration.GetSection("DownstreamApi"))
because I am usingGraph API SDK
and reading scope fromappsettings.json
so in the sample I am using local scope for your test case. So its not required or upto you.
Controller Action:
public async Task<object> GetUserInfoFromGraphAPI()
{
try
{
//Initialize on behalf of user token aquisition service
var _tokenAcquisition = this.HttpContext.RequestServices.GetRequiredService<ITokenAcquisition>() as ITokenAcquisition;
//define the scope
string[] scopes = new string[] { "https://graph.microsoft.com/.default" };
//Getting token from Azure Active Directory
string accessToken = await _tokenAcquisition.GetAccessTokenForUserAsync(scopes);
//Request Grap API end point
HttpClient _client = new HttpClient();
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, string.Format("https://graph.microsoft.com/v1.0/me"));
//Passing Token For this Request
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
HttpResponseMessage response = await _client.SendAsync(request);
//Get User into from grpah API
dynamic userInfo = JsonConvert.DeserializeObject<dynamic>(await response.Content.ReadAsStringAsync());
return userInfo;
}
catch (Exception ex)
{
throw;
}
}
Output:
Note: For complete solution please visit the GitHub Link
Hope it will help you to achive your goal.