I am trying to create a .net core 6 Web Api that calls Microsoft Graph on behalf of what amounts to be an eventual Vue.Js client end user (with office 365 account and Azure Active Directory Registered). I haven't setup the client but I am trying to test the web api to make sure everythings working and my api calls all response with 204 (No Content). Postman also returns the same on those api calls. I suspect I haven't set the Graph Service Client up correctly but I can't find a way to fix it.
I setup authentication in my ConfigureServices like so
// Enable JWT Bearer Authentication
services.AddAuthentication(sharedOptions =>
{
sharedOptions.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
Configuration.Bind("AzureAd", options);
// Authority will be Your AzureAd Instance and Tenant Id
options.Authority = $"{Configuration["AzureAd:Instance"]}{Configuration["AzureAd:TenantId"]}/v2.0";
// The valid audiences are both the Client ID(options.Audience) and api://{ClientID}
options.TokenValidationParameters.ValidAudiences = new string[] { Configuration["AzureAd:ClientId"], $"api://{Configuration["AzureAd:ClientId"]}" };
});
var options = new TokenCredentialOptions
{
AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
};
var authCodeCredential = new AuthorizationCodeCredential(Configuration["AzureAd:TenantId"], Configuration["AzureAd:ClientId"], Configuration["AzureAd:ClientSecret"],
$"{Configuration["AzureAd:Instance"]}{Configuration["AzureAd:TenantId"]}/oauth2/v2.0/authorize", options);
services.AddSingleton<GraphServiceClient>(_ => new GraphServiceClient(authCodeCredential, Configuration.GetValue<string>("DownstreamApi:Scopes")?.Split(', ')));
AddSwagger(services);
With AddSwagger Being
services.AddOpenApiDocument(document =>
{
document.AddSecurity("bearer", Enumerable.Empty<string>(), new NSwag.OpenApiSecurityScheme
{
Type = OpenApiSecuritySchemeType.OAuth2,
Description = "Azure AAD Authentication",
Flow = OpenApiOAuth2Flow.Implicit,
Flows = new NSwag.OpenApiOAuthFlows()
{
Implicit = new OpenApiOAuthFlow()
{
Scopes = new Dictionary<string, string>
{
{ $"api://{Configuration["AzureAd:ClientId"]}/user_impersonation", "Access Application" },
},
AuthorizationUrl = $"{Configuration["AzureAd:Instance"]}{Configuration["AzureAd:TenantId"]}/oauth2/v2.0/authorize",
TokenUrl = $"{Configuration["AzureAd:Instance"]}{Configuration["AzureAd:TenantId"]}/oauth2/v2.0/token",
},
},
});
document.OperationProcessors.Add(new AspNetCoreOperationSecurityScopeProcessor("bearer"));
});
And then Create and User my GraphClient in the controller like So
private readonly GraphServiceClient _graphServiceClient;
public GraphController(GraphServiceClient graphServiceClient)
{
this._graphServiceClient = graphServiceClient;
}
[Authorize]
[HttpGet("GetUserDetails")]
public async Task<User> GetUserDetails()
{
try
{
User user = await _graphServiceClient.Me.Request().GetAsync();
return user;
}
catch (Exception ex)
{
return null;
}
}
CodePudding user response:
I followed this document.
If you want to use graph client
to call graph api, then you need to set the auth provider first. This is mentioned in the document I mentioned, you need to add AddMicrosoftGraph
.This will make an authenticated GraphServiceClient available to controllers via dependency injection.
services.AddMicrosoftIdentityWebAppAuthentication(Configuration)
.EnableTokenAcquisitionToCallDownstreamApi(new string[] { "user.read" })
.AddMicrosoftGraph(options =>
{
options.Scopes = string.Join(' ', new string[] { "user.read" });
})
.AddInMemoryTokenCaches();
Or this code instead.
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
// Specify this is a web app and needs auth code flow
//.AddMicrosoftIdentityWebApp(Configuration)
// Add ability to call web API (Graph)
// and get access tokens
.EnableTokenAcquisitionToCallDownstreamApi(new string[] { "user.read" })
//need to install Microsoft.Identity.Web.MicrosoftGraph
//Add a GraphServiceClient via dependency injection
.AddMicrosoftGraph(options =>
{
options.Scopes = string.Join(' ', new string[] { "user.read" });
})
// Use in-memory token cache
// See https://github.com/AzureAD/microsoft-identity-web/wiki/token-cache-serialization
.AddInMemoryTokenCaches();
My packages installed:
<ItemGroup>
<PackageReference Include="Microsoft.Graph" Version="4.19.0" />
<PackageReference Include="Microsoft.Identity.Web" Version="1.23.0" />
<PackageReference Include="Microsoft.Identity.Web.MicrosoftGraph" Version="1.23.0" />
<PackageReference Include="Microsoft.Identity.Web.UI" Version="1.23.0" />
</ItemGroup>
CodePudding user response:
The issue ended up being the
authCodeCredential = new AuthorizationCodeCredential(Configuration["AzureAd:TenantId"], Configuration["AzureAd:ClientId"], Configuration["AzureAd:ClientSecret"],
$"{Configuration["AzureAd:Instance"]}{Configuration["AzureAd:TenantId"]}/oauth2/v2.0/authorize", options);
services.AddSingleton<GraphServiceClient>(_ => new GraphServiceClient(authCodeCredential, Configuration.GetValue<string>("DownstreamApi:Scopes")?.Split(', ')));
Where the authorization code being passed in was incorrect. Unsure of how to fix this at the moment but replacing this line of code with a UsernamePasswordCredential instead gave the correct outputs.