Search code examples
asp.net-coremicrosoft-graph-apiasp.net-identity

ASP.NET Core and Microsoft Graph


I've an ASP.NET Core web application. Users can login with username and password or with Azure AD.

In a page with many info I want to show an info from Graph (e.g. Unread emails counter) only for Azure AD users. Other users simply can view the page, without the "Unread emails counter" info.

I don't understand how to make it work. The problem is that Graph works only if I decorate the page with [Authorize(AuthenticationSchemes = OpenIdConnectDefaults.AuthenticationScheme)]

but to allow other users to access the same page I cannot use that attribute.

Both

[Authorize(AuthenticationSchemes = $"{OpenIdConnectDefaults.AuthenticationScheme},{CookieAuthenticationDefaults.AuthenticationScheme}")]

and

[AllowAnonymous]
[Authorize(AuthenticationSchemes = OpenIdConnectDefaults.AuthenticationScheme)]

works for other users but do not works for Azure AD users because Graph throw exception

InvalidOperationException: IDW10503: Cannot determine the cloud Instance. The provided authentication scheme was ''. Microsoft.Identity.Web inferred 'Cookies' as the authentication scheme. Available authentication schemes are 'Cookies,OpenIdConnect'.

Here some code for your reference:

Authentication

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddNegotiate()
    .AddMicrosoftIdentityWebApp(builder.Configuration, configSectionName: "Authentication:AzureAD");

builder.Services.AddRazorPages()
    .AddMicrosoftIdentityUI();

var app = builder.Build();

app.UseSession();

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

app.MapRazorPages();

app.Run();

The Razor Page

[Authorize(AuthenticationSchemes = OpenIdConnectDefaults.AuthenticationScheme)]
[Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme)]
public class GraphCMSModel : PageModel
{
    private readonly GraphLogic _graphLogic;

    public string Message { get; set; } = string.Empty;

    public GraphCMSModel(GraphLogic graphLogic)
    {
        _graphLogic = graphLogic;
    }

    public async Task OnGetAsync()
    {
        if (AuthHelper.IsAzureAdAuthenticated)
        {
            var messages = await _graph.Me.MailFolders["Inbox"].Messages
                                  .Request()
                                  .Filter("isRead ne true")
                                  .GetAsync();
            Message = $"You have {messages.Count} unread messages";
        }
        else
        {
            Message = "No Graph for you";
        }
    }
}

Solution

  • I've found a way to tell GraphServiceClient what authentication schema to use using WithAuthenticationScheme method:

    var messages = await graph.Me.MailFolders["Inbox"].Messages
        .Request()
        .WithAuthenticationScheme(OpenIdConnectDefaults.AuthenticationScheme)
        .Filter("isRead ne true")
        .GetAsync();