question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Multiple Authentication Schemes are mutually exclusive

See original GitHub issue

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

I have a React SPA and a Mobile App that calls a Web API protected by Azure AD OIDC.

  • The React SPA uses the default JWT authentication scheme provided by the AddMicrosoftIdentityWebApi() extension
  • The Mobile App uses a custom HTTP Header-based authentication scheme

Goal: If AT LEAST one of the schemes succeeds then the user should be authenticated. Unfortunately the two schemes are mutually exclusive:

  • If I set AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme) then the React SPA authenticates the user but the Mobile App returns 401
  • If I set AddAuthenticationSchemes(MobileAuthenticationDefaults.AuthenticationScheme) then the Mobile App authenticates the user but the React SPA returns 401

Expected Behavior

Both React SPA and Mobile App should be able to authenticate using their separate authentication schemes.

Steps To Reproduce

startup.cs example with JWT default:

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                .AddScheme<MobileAuthenticationSchemeOptions, MobileAuthenticationHandler>(MobileAuthenticationDefaults.AuthenticationScheme, null)
                .AddMicrosoftIdentityWebApi(Configuration.GetSection("AzureAD:LycheeWebAPI"));
services.AddAuthorization(options =>
            {
                options.DefaultPolicy = new AuthorizationPolicyBuilder(
                    JwtBearerDefaults.AuthenticationScheme,
                    MobileAuthenticationDefaults.AuthenticationScheme)
                    .RequireAuthenticatedUser()
                    .Build();
            });
services.AddScoped<IAuthenticationHandler, MobileAuthenticationHandler>();
...
var policy = new AuthorizationPolicyBuilder()
                .AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme, MobileAuthenticationDefaults.AuthenticationScheme)
                .RequireAuthenticatedUser()
                .Build();
mvcOptions.Filters.Add(new AuthorizeFilter(policy));
...
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");
            });

MobileAuthenticationHandler:

public class MobileAuthenticationHandler : AuthenticationHandler<MobileAuthenticationSchemeOptions>
{
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
        {
            // validation comes in here
            if (!Request.Headers.ContainsKey(ApiConstants.MobileApiHttpHeader))
            {
                return Task.FromResult(AuthenticateResult.NoResult());
            }
            ...
            var claimsIdentity = new ClaimsIdentity(claims, nameof(MobileAuthenticationHandler));
            var ticket = new AuthenticationTicket(
                new ClaimsPrincipal(claimsIdentity), this.Scheme.Name);
            return Task.FromResult(AuthenticateResult.Success(ticket));
}

MobileAuthenticationOptions.cs:

public class MobileAuthenticationSchemeOptions : AuthenticationSchemeOptions
{
}

MobileAuthenticationDefaults.cs:

public static class MobileAuthenticationDefaults
{
    public const string AuthenticationScheme = "MobileAuthenticationScheme";
}

Exceptions (if any)

N/A

.NET Version

6.0.101

Anything else?

  • ASP.NET Core 5
  • VS 2022 Community
.NET SDK (reflecting any global.json):
 Version:   6.0.101
 Commit:    ef49f6213a

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.19043
 OS Platform: Windows
 RID:         win10-x64
 Base Path:   C:\Program Files\dotnet\sdk\6.0.101\

Host (useful for support):
  Version: 6.0.3
  Commit:  c24d9a9c91

.NET SDKs installed:
  6.0.101 [C:\Program Files\dotnet\sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.App 5.0.13 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 5.0.15 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 6.0.1 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 6.0.3 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 5.0.13 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 5.0.15 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.1 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.3 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.WindowsDesktop.App 5.0.13 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 5.0.15 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 6.0.1 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

Issue Analytics

  • State:open
  • Created a year ago
  • Reactions:1
  • Comments:19 (13 by maintainers)

github_iconTop GitHub Comments

2reactions
HaoKcommented, Mar 22, 2022

Or maybe we should just add a ne example of this pick first scheme that succeeds Authenticate to the policyschemes docs

1reaction
HaoKcommented, Mar 22, 2022

I guess if we wanted to make this in the box, we could also just add the concept of FallbackAuthenticateScheme to our default implementation so this kind of thing just works for authenticate (check yourself for authentication, if you don’t have anything, then fallback to the FallbackAuthenticateScheme), its basically a second Foward, but instead of always forwarding, you only fallback

Read more comments on GitHub >

github_iconTop Results From Across the Web

Skip Authentication Schemes in ASP.NET Core
Learn how to fine-tune the authentication middleware and skip authentication schemes in ASP.NET Core; complete with examples!
Read more >
Mutual authentication
Mutual authentication or two-way authentication refers to two parties authenticating each other at the same time in an authentication protocol.
Read more >
How to Use Multiple Authentication Schemes in .NET
In this article, we are going to learn how to use multiple authentication schemes in .NET 6 at the same time.
Read more >
5 Configuring User Authentication
For chained authentication, an authentication scheme contains multiple steps linked ... Redirection and use of header variables are mutually exclusive.
Read more >
Asp.net multiple authenticaiton schemes | 32 comments
NET: Multiple Authentication Schemes Usually, in the Api you have one identity ... constants are generally used for lists of mutually exclusive elements....
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found