Good morning
I have an ASP.net Core app, this app list all the users in the organization of the user who is login.
I made the login using the Authorization Code Flow and ask for delegated permissions to list users, see calendar, etc.
This is the code I used to authenticate the user
var builder = WebApplication.CreateBuilder(args);
// Configure authentication
builder.Services
// Use OpenId authentication
.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
// Specify this is a web app and needs auth code flow
.AddMicrosoftIdentityWebApp(options =>
{
builder.Configuration.Bind("AzureAd", options);
// This causes the signin to prompt the user for which
// account to use - useful when there are multiple accounts signed
// into the browser
options.Prompt = "select_account";
options.Events.OnTokenValidated = async context =>
{
var tokenAcquisition = context.HttpContext.RequestServices
.GetRequiredService<ITokenAcquisition>();
var graphClient = new GraphServiceClient(
new BaseBearerTokenAuthenticationProvider(
new TokenAcquisitionTokenProvider(
tokenAcquisition,
GraphConstants.Scopes,
context.Principal)));
// Get user information from Graph
var user = await graphClient.Me
.GetAsync(config =>
{
config.QueryParameters.Select =
["displayName", "mail", "mailboxSettings", "userPrincipalName"];
});
context.Principal?.AddUserGraphInfo(user);
};
options.Events.OnAuthenticationFailed = context =>
{
var error = WebUtility.UrlEncode(context.Exception.Message);
context.Response
.Redirect($"/Home/ErrorWithMessage?message=Authentication+error&debug={error}");
context.HandleResponse();
return Task.FromResult(0);
};
options.Events.OnRemoteFailure = context =>
{
if (context.Failure is OpenIdConnectProtocolException)
{
var error = WebUtility.UrlEncode(context.Failure.Message);
context.Response
.Redirect($"/Home/ErrorWithMessage?message=Sign+in+error&debug={error}");
context.HandleResponse();
}
return Task.FromResult(0);
};
})
// Add ability to call web API (Graph)
// and get access tokens
.EnableTokenAcquisitionToCallDownstreamApi(
options =>
{
builder.Configuration.Bind("AzureAd", options);
},
GraphConstants.Scopes)
// Add a GraphServiceClient via dependency injection
.AddMicrosoftGraph(options =>
{
options.Scopes = GraphConstants.Scopes;
})
// Use in-memory token cache
// See https://github.com/AzureAD/microsoft-identity-web/wiki/token-cache-serialization
.AddInMemoryTokenCaches();
// Require authentication
builder.Services
.AddControllersWithViews(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
})
// Add the Microsoft Identity UI pages for sign in/out
.AddMicrosoftIdentityUI();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
Now I need to implement callings features, for this I need to get access to Applications Permissions which mean I have to create the Client Credentials Flow
There is a way to keep both?
I tried to add this piece of code
// Add the Microsoft Identity Web App services for Client Credentials Flow
builder.Services.AddMicrosoftIdentityWebAppAuthentication(builder.Configuration, "Azure")
.EnableTokenAcquisitionToCallDownstreamApi(
options =>
{
builder.Configuration.Bind("Azure", options);
},
GraphConstants.ScopesApp)
.AddInMemoryTokenCaches();
What I think mean I'm trying to authenticate 2 times in the same Schema.
Any Idea to keep both flows?

The exception is due to adding the same scheme name in authentication mechanism.
builder.Services.AddMicrosoftIdentityWebAppAuthentication(builder.Configuration, "Azure")is equal tobuilder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme).AddMicrosoftIdentityWebApp()which are both used to integrate microsoft identity platform into the app, using auth code flow. So that you shouldn't add the last piece of code.Try to add client credential flow into your app, you can use code below. Please note, using client credential flow means you are trying to generate access token without users sign in, so that this code can be added anywhere you want to generate token or call graph api, it won't have conflict with the feature you already had in your
Program.cs.In your scenario, you already add graph SDK into your code, so that you can inject graphServiceClient into Controller and use delegated permission to call graph api, you can also use my code below to new another graphServiceClient to call graph api with application permission. Let's see a sample which have 2 graphServiceClient together.