9

We're working on an API that allows users authenticating through a number of different providers. The individual providers are not an issue, but using them together is proving to be a challenge.

It seems that adding more than 1 provider throws a InvalidOperationException with "Scheme already exists: Bearer" when the application starts up.

Below is the ConfigureServices function from Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer(options =>
        {
            options.Authority = "Value";
            options.Audience = "Value";
        })
        .AddMicrosoftIdentityWebApi(options =>
        {
            Configuration.Bind("AzureAdB2C", options);

            options.TokenValidationParameters.NameClaimType = "name";
        },
        options => { Configuration.Bind("AzureAdB2C", options); });
    
    services.AddControllers();
    services.AddAuthorization(options =>
    {
        options.DefaultPolicy = new AuthorizationPolicyBuilder(
            JwtBearerDefaults.AuthenticationScheme)
            .RequireAuthenticatedUser()
            .Build();
    });
}

I'm using the Microsoft example for authenticating with Azure AD as a starting point. Removing either the AddJwtBearer or AddMicrosoftIdentityWebApi calls works fine, but I need to configure both providers for our use-case.

Is there a way to do this with .NET Core 3.1 or up?

Ravikumar B
  • 779
  • 1
  • 14
  • 25
Nino van der Mark
  • 622
  • 1
  • 9
  • 19
  • 2
    the error does make sense, looks like internally the scheme `Bearer` is used by both providers. I think they may have some option to change the scheme, if not looks like you need to write your own provider which combines both those providers. That's the logic to solve this issue, but I've actually never done something similar before. – Hopeless Nov 18 '20 at 16:37
  • 1
    Did you find a way for this? I am also looking for solution on this – Ravikumar B Feb 09 '21 at 06:08
  • 2
    No, not yet. For our solution we've been able to make the concession that we'll only use 1 of these during the lifetime of the application, as we generally won't mix and match in any production scenario's. That said it's probably possible to dissect the `AddJwtBearer` call and specify a different scheme so that it doesn't collide with the `Bearer` scheme used in the `AddMicrosoftIdentityWebApi` call. If I have some spare time I'll try to whip up an example as an answer :) – Nino van der Mark Feb 09 '21 at 07:40

1 Answers1

10

We can't register 2 authentications under same scheme name. So we need to register the 2 authentication schemes with different name(or one with default and another with a scheme name) In my case I am registering 2 authentication schemes:

  1. My own JWT scheme with our app name "MyAppName",
  2. Azure AD authentication with JWT default scheme JwtBearerDefaults.AuthenticationScheme, as I was not able to add it with custom scheme name.

I was able to make it work with the following configuration:

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer("MyAppName",options =>
    {
         options.Authority = "Value";
         options.Audience = "Value";                    
    })
    .AddMicrosoftIdentityWebApi(Configuration, "AzureAd");

and Authorization configuration:

services.AddAuthorization(options =>
{
    options.DefaultPolicy = new AuthorizationPolicyBuilder(
        "MyAppName",
        JwtBearerDefaults.AuthenticationScheme)
    .RequireAuthenticatedUser()
    .Build();
});
Nino van der Mark
  • 622
  • 1
  • 9
  • 19
Ravikumar B
  • 779
  • 1
  • 14
  • 25
  • Had high hopes but unfortunately after doing so it doesn't work. Seems that .net gets confused which type of bearer token is send to the server. When I login with a username+password the generated Bearer token returns an error when used: `www-authenticate: Bearer error="invalid_token",error_description="The signature key was not found"` – CularBytes Aug 19 '22 at 14:01
  • 1
    After reading this answer: https://stackoverflow.com/a/49706390/2901207 I've got it working. Eventually it is similar but does include a bit more of explenation. – CularBytes Aug 20 '22 at 10:06