dotnet / dotnet/aspnetcore

Multiple Authentication Schemes are mutually exclusive

Open
#40,820 19 comments 4 reactions 0 assignees View on GitHub
area-auth Docs
Dominant language
C#
Stars
38.4k
Forks
10.9k
Avg merge
2d 6h
Merged PRs (30d)
290

Description

### Is there an existing issue for this?

- [X] 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:
```c#
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddScheme(MobileAuthenticationDefaults.AuthenticationScheme, null)
.AddMicrosoftIdentityWebApi(Configuration.GetSection("AzureAD:LycheeWebAPI"));
services.AddAuthorization(options =>
{
options.DefaultPolicy = new AuthorizationPolicyBuilder(
JwtBearerDefaults.AuthenticationScheme,
MobileAuthenticationDefaults.AuthenticationScheme)
.RequireAuthenticatedUser()
.Build();
});
services.AddScoped();
...
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:
```c#
public class MobileAuthenticationHandler : AuthenticationHandler
{
protected override Task 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:
```c#
public class MobileAuthenticationSchemeOptions : AuthenticationSchemeOptions
{
}
```

MobileAuthenticationDefaults.cs:
```c#
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]
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.