Skip to content

InvalidOperationException: The authentication handler registered for scheme 'bearer' is 'JwtBearerHandler' which cannot be used for SignInAsync #52151

@AndriiLobanov

Description

@AndriiLobanov

My task is to do JWT authentication. My application is using .NET 6 and ASP NET MVC. I obtain a JWT access token during server-side authentication using OpenID Connect and then have it automatically added to the request headers for your authorized API calls.
My code in Program.cs:

const string AUTH_COOKIE_NAME = "access_token";
const string AUTH_SCHEMA_NAME = "OPENIDC_JWT";
const string BEARER_AUTH_SCHEMA_NAME = "bearer";
const string OIDC_AUTH_SCHEMA_NAME = "oidc";

builder.Services.AddAuthentication(options => {

    options.DefaultScheme = AUTH_SCHEMA_NAME;
    options.DefaultAuthenticateScheme = OIDC_AUTH_SCHEMA_NAME;
    options.DefaultChallengeScheme = OIDC_AUTH_SCHEMA_NAME;
})
    .AddOpenIdConnect(OIDC_AUTH_SCHEMA_NAME, o =>
    {
        o.MetadataAddress = builder.Configuration["SingleSignOn:MetaData"];
        o.Authority = builder.Configuration["SingleSignOn:Authority"];
        o.ClientId = builder.Configuration["SingleSignOn:ClientId"];
        o.ClientSecret = builder.Configuration["SingleSignOn:ClientSecret"];
        o.ResponseType = OpenIdConnectResponseType.Code;
        o.SaveTokens = true;
        o.Scope.Clear();
        o.Scope.Add("openid");
        o.Scope.Add("email");
        o.CallbackPath = "/signin-oidc";
        o.AccessDeniedPath = "/Account/AccessDenied";
        o.SignInScheme = BEARER_AUTH_SCHEMA_NAME;
        
        o.Events = new OpenIdConnectEvents
        {
            OnTokenValidated = async context =>
            {
                var accessToken = context.SecurityToken as JwtSecurityToken;
                if (accessToken != null)
                {
                    // Store the access token in the authentication properties
                    context.Properties.StoreTokens(new[]
                    {
                        new AuthenticationToken { Name = OpenIdConnectParameterNames.AccessToken, Value = accessToken.RawData },
                    });
                }
               
                context.Request.Headers.Append("Authorization", $"Bearer {accessToken.RawData}");
                var roleService = context.HttpContext.RequestServices.GetRequiredService<IUserRolesService>();
                roleService.ManageUserRoles(context);
            },
        };
    })
    .AddJwtBearer(BEARER_AUTH_SCHEMA_NAME, options =>
    {
        options.MetadataAddress = "https://access-staging.epam.com/auth/realms/plusx/.well-known/openid-configuration";
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true, // You shoud set ValidateAudience = true and specify ValidAudience for your application.
            ValidAudience = builder.Configuration["SingleSignOn:ClientId"],
            ValidateIssuerSigningKey = true,
        };
        options.Events = new JwtBearerEvents
        {
            OnMessageReceived = context =>
            {
                string authCookie = context.Request.Cookies[AUTH_COOKIE_NAME];

                // Token will be taken from Authorization header or if header is not set from authentication cookie.
                if (!string.IsNullOrEmpty(authCookie))
                {
                    context.Token = authCookie;
                }
                return Task.CompletedTask;
            }
        };
    })
    .AddPolicyScheme(AUTH_SCHEMA_NAME, AUTH_SCHEMA_NAME, options =>
    {
        options.ForwardDefaultSelector = context =>
        {
            string authHeader = context.Request.Headers[HeaderNames.Authorization];
            string authCookie = context.Request.Cookies[AUTH_COOKIE_NAME];

            // If Token presents in header or cookie choose "bearer" schema, in other case use "oidc" schema.
            if (!string.IsNullOrEmpty(authHeader) || !string.IsNullOrEmpty(authCookie))
                return BEARER_AUTH_SCHEMA_NAME;

            return OIDC_AUTH_SCHEMA_NAME;
        };
    });

builder.Services.AddAuthorization();

// more services

var app = builder.Build();

AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}
else
{
    app.UseExceptionHandler("/Home/Error");
    app.UseHsts();//HTTP Strict Transport Security Protocol is used to be sure that none of your content is still server over HTTP
}

app.UseHttpsRedirection();  
app.UseStaticFiles();
app.UseMiddleware<SecurityHeadersMiddleware>();
app.UseRouting();
app.UseAuthentication();

app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Admin}/{action=Index}/{id?}");

app.Run();

As you can see from the code, I authenticate to my company via OpenIdConnect, receive a JWT access token and insert it into the headers for further communication with other services in my company via this JWT token. When a client needs to call protected API endpoints, it must include the JWT token in the Authorization header with the Bearer scheme, like this:

Authorization: Bearer your_jwt_token

Trace of the error: the context goes into the services, where, depending on the user’s email, they are assigned claims. Example of the service:

public void ManageUserRoles(TokenValidatedContext context)
{
    var user = context.Principal;

    if (user.Identity.IsAuthenticated)
    {
        if (!user.HasClaim(c => c.Type == ClaimTypes.Role))
        {
          if (!string.IsNullOrEmpty(userEmail) && isAdmin)
           {
             _logger.LogInformation($"Set the '{RoleNames.Admin}' role to user with email:  '{userEmail}'");
              identity.AddClaim(new Claim(ClaimTypes.Role, RoleNames.Admin));
            }
         }
}

My error occurs just after I leave the event OnTokenValidated:InvalidOperationException: The authentication handler registered for scheme 'bearer' is 'JwtBearerHandler' which cannot be used for SignInAsync. The registered sign-in schemes are: OPENIDC_JWT.
am using AddPolicyScheme like handler in case if I have JWT token in header, I am using JWTBearer authentication, validate the token and go into my application on localhost; else if JWT token is null in the header, I must authenticate through my company's Identity provider, receive token, add it to the header, then validate it in AddJwtBearer and authorize into my application.

Also to mention, I have the attribute [Authorize] on all my controllers. And do not offer me to use .AddCookie in authentication service or use cookies-based authentication schemes.

I tried using only Bearer authentication scheme as default:

builder.Services.AddAuthentication(options => {

    options.DefaultScheme = BEARER_AUTH_SCHEMA_NAME;
   
})

after that nothing is happening.

I tried to use different variations of schemes in authentication schemes:

options.DefaultScheme = AUTH_SCHEMA_NAME;
options.DefaultAuthenticateScheme = AUTH_SCHEMA_NAME;
options.DefaultChallengeScheme = AUTH_SCHEMA_NAME;

-- the same error after that: InvalidOperationException: The authentication handler registered for scheme 'bearer' is 'JwtBearerHandler' which cannot be used for SignInAsync. The registered sign-in schemes are: OPENIDC_JWT.

Tried to use only one Default Scheme:

`options.DefaultScheme = AUTH_SCHEMA_NAME;`

After that the same error: InvalidOperationException: The authentication handler registered for scheme 'bearer' is 'JwtBearerHandler' which cannot be used for SignInAsync. The registered sign-in schemes are: OPENIDC_JWT.

Tried also this variant:

builder.Services.AddAuthentication(options => {

    options.DefaultScheme = BEARER_AUTH_SCHEMA_NAME;
    options.DefaultChallengeScheme = OIDC_AUTH_SCHEMA_NAME;
})

After that the same error: InvalidOperationException: The authentication handler registered for scheme 'bearer' is 'JwtBearerHandler' which cannot be used for SignInAsync. The registered sign-in schemes are: OPENIDC_JWT.

Stack trace:

System.InvalidOperationException: The authentication handler registered for scheme 'bearer' is 'JwtBearerHandler' which cannot be used for SignInAsync. The registered sign-in schemes are: OPENIDC_JWT.

   at Microsoft.AspNetCore.Authentication.AuthenticationService.SignInAsync(HttpContext context, String scheme, ClaimsPrincipal principal, AuthenticationProperties properties)

   at Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler`1.HandleRequestAsync()

   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)

   at Middlewares.SecurityHeadersMiddleware.InvokeAsync(HttpContext context) in Middlewares\SecurityHeadersMiddleware.cs:line 23

   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-authIncludes: Authn, Authz, OAuth, OIDC, Bearer

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions