Skip to content

Blazor with multiple auth middleware #14916

@aL3891

Description

@aL3891

Describe the bug

When using multiple auth middleware (AzureAD and AzureAdBearer in my case) blazor seems unable to find the logged in user. The user is logged in though, its presented with the azure login ui and visiting a non-blazor page does correctly show the logged in user.

To Reproduce

Steps to reproduce the behavior:

  1. Create a new blazor server app in visual studio, with work/School auth.

  2. In Startup.cs, replace the AddAuthentication and AddControllersWithViews calls with the following

     services.AddAuthentication(options => { options.DefaultChallengeScheme = AzureADDefaults.AuthenticationScheme; })
         .AddAzureAD(options => Configuration.Bind("AzureAd", options))
         .AddAzureADBearer(options => Configuration.Bind("AzureAd", options));
     
     services.AddControllersWithViews(options =>
     {
         var policy = new AuthorizationPolicyBuilder(AzureADDefaults.BearerAuthenticationScheme, AzureADDefaults.AuthenticationScheme)
             .RequireAuthenticatedUser().Build();
         options.Filters.Add(new AuthorizeFilter(policy));
     });
    
  3. Run and login

Expected behavior

The blazor app should show the logged in user but blazor in particular seems unable to do so.

looking at the output [with some static file stuff removed]

        Request starting HTTP/2 GET https://localhost:5001/
  info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0]
        Executing endpoint '/_Host'
  info: Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker[3]
        Route matched with {page = "/_Host", area = "", action = "", controller = ""}. Executing page /_Host
  info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[1]
        Authorization was successful.
  info: Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker[103]
        Executing an implicit handler method - ModelState is Valid
  info: Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker[104]
        Executed an implicit handler method, returned result Microsoft.AspNetCore.Mvc.RazorPages.PageResult.
  info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[1]
        Authorization was successful.
  info: Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker[4]
        Executed page /_Host in 137.3536ms
  info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
        Executed endpoint '/_Host'
  info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
        Request finished in 175.8487ms 200 text/html; charset=utf-8
  info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
        Request starting HTTP/2 POST https://localhost:5001/_blazor/negotiate text/plain;charset=UTF-8 0
  info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0]
        Executing endpoint '/_blazor/negotiate'
  info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
        Executed endpoint '/_blazor/negotiate'
  info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
        Request finished in 17.318ms 200 application/json
  info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
        Request starting HTTP/1.1 GET https://localhost:5001/_blazor?id=NhnoRIeHHoiihpkIjnUnCg
  info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0]
        Executing endpoint '/_blazor'
  info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2]
        Authorization failed.

It seems like authorization is successful when serving the _host but then fails later.

Additional context

There are few significant notes about this setup. AzureAD and AzureADBearer is used to use the AzureAD challenge if no auth is provided. In other words, you're ment to be able to open the app in a browser and enter the user login flow, or for a script to make a call to an api using a bearer token as well.

This means the auth filter must specify the Bearer auth first and the AzureAD second, otherwise the Bearer auth overwrites the AzureAD challenge response as user browses to a page. (at least this is my understanding)

i notice though that the log only prints out one auth middleware at the end of the log there, so i wonder if blazor only checks the first auth middleware, the bearer in my case, witch isn't authorized while missing the auth middleware that actually is authorized, i'm just guessing here though

The first request looks like this and calls both auth middlewares

info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
      Request starting HTTP/2 GET https://localhost:5001/
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0]
      Executing endpoint '/_Host'
info: Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker[3]
      Route matched with {page = "/_Host", area = "", action = "", controller = ""}. Executing page /_Host
info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2]
      Authorization failed.
info: Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker[3]
      Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'.
info: Microsoft.AspNetCore.Mvc.ChallengeResult[1]
      Executing ChallengeResult with authentication schemes (AzureADBearer, AzureAD).
info: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler[12]
      AuthenticationScheme: AzureADJwtBearer was challenged.
info: Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler[12]
      AuthenticationScheme: AzureADOpenID was challenged.
info: Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker[4]
      Executed page /_Host in 474.51980000000003ms
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
      Executed endpoint '/_Host'
info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
      Request finished in 580.8627ms 302

i'm using the latest vs preview and 3.0.100 of the dotnet sdk

This issue also seems a bit similar to #13709 but not quite the same

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-blazorIncludes: Blazor, Razor Components

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions