Skip to content

Commit 720559f

Browse files
Merge pull request #34310 from damienbod/damienbod/jwt-bearer-authn
Configure JWT bearer authentication in ASP.NET Core
2 parents b34d888 + eb63d3c commit 720559f

File tree

10 files changed

+505
-0
lines changed

10 files changed

+505
-0
lines changed

aspnetcore/security/authentication/configure-jwt-bearer-authentication.md

Lines changed: 330 additions & 0 deletions
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using Microsoft.AspNetCore.Authorization;
2+
using Microsoft.AspNetCore.Mvc;
3+
4+
namespace JwtBearer.Controllers;
5+
6+
[Authorize]
7+
[ApiController]
8+
[Route("[controller]")]
9+
public class WeatherForecastController : ControllerBase
10+
{
11+
private static readonly string[] Summaries =
12+
[
13+
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
14+
];
15+
16+
[HttpGet(Name = "GetWeatherForecast")]
17+
public IEnumerable<WeatherForecast> Get()
18+
{
19+
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
20+
{
21+
Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
22+
TemperatureC = Random.Shared.Next(-20, 55),
23+
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
24+
})
25+
.ToArray();
26+
}
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<Project Sdk="Microsoft.NET.Sdk.Web">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net9.0</TargetFramework>
5+
<Nullable>enable</Nullable>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.0" />
11+
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.0" />
12+
</ItemGroup>
13+
14+
</Project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
@JwtBearer_HostAddress = https://localhost:7279
2+
3+
GET {{JwtBearer_HostAddress}}/weatherforecast/
4+
Accept: application/json
5+
6+
###
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
2+
using Microsoft.AspNetCore.Authentication.JwtBearer;
3+
4+
namespace JwtBearer;
5+
6+
public class Program
7+
{
8+
public static void Main(string[] args)
9+
{
10+
var builder = WebApplication.CreateBuilder(args);
11+
12+
builder.Services.AddControllers();
13+
builder.Services.AddOpenApi();
14+
15+
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
16+
.AddJwtBearer(jwtOptions =>
17+
{
18+
jwtOptions.Authority = "https://{--your-authority--}";
19+
jwtOptions.Audience = "https://{--your-audience--}";
20+
});
21+
22+
var app = builder.Build();
23+
24+
if (app.Environment.IsDevelopment())
25+
{
26+
app.MapOpenApi();
27+
}
28+
29+
app.UseHttpsRedirection();
30+
31+
app.UseAuthorization();
32+
33+
app.MapControllers();
34+
35+
app.Run();
36+
}
37+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
namespace JwtBearer;
2+
3+
public class WeatherForecast
4+
{
5+
public DateOnly Date { get; set; }
6+
7+
public int TemperatureC { get; set; }
8+
9+
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
10+
11+
public string? Summary { get; set; }
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"Logging": {
3+
"LogLevel": {
4+
"Default": "Information",
5+
"Microsoft.AspNetCore": "Warning"
6+
}
7+
}
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"Logging": {
3+
"LogLevel": {
4+
"Default": "Information",
5+
"Microsoft.AspNetCore": "Warning"
6+
}
7+
},
8+
"AllowedHosts": "*"
9+
}

aspnetcore/security/authentication/policyschemes.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,66 @@ All authentication schemes that use derived <xref:Microsoft.AspNetCore.Authentic
2121

2222
[!code-csharp[sample](policyschemes/samples/AuthenticationSchemeOptions.cs?name=snippet)]
2323

24+
## JWT with multiple schemes
25+
26+
The AddPolicyScheme method can define multiple authentication schemes and implement logic to select the appropriate scheme based on token properties (e.g., issuer, claims). This approach allows for greater flexibility within a single API.
27+
28+
```csharp
29+
services.AddAuthentication(options =>
30+
{
31+
options.DefaultScheme = Consts.MY_POLICY_SCHEME;
32+
options.DefaultChallengeScheme = Consts.MY_POLICY_SCHEME;
33+
34+
})
35+
.AddJwtBearer(Consts.MY_FIRST_SCHEME, options =>
36+
{
37+
options.Authority = "https://your-authority";
38+
options.Audience = "https://your-audience";
39+
options.TokenValidationParameters = new TokenValidationParameters
40+
{
41+
ValidateIssuer = true,
42+
ValidateAudience = true,
43+
ValidateIssuerSigningKey = true,
44+
ValidAudiences = Configuration.GetSection("ValidAudiences").Get<string[]>(),
45+
ValidIssuers = Configuration.GetSection("ValidIssuers").Get<string[]>()
46+
};
47+
})
48+
.AddJwtBearer(Consts.MY_AAD_SCHEME, jwtOptions =>
49+
{
50+
jwtOptions.Authority = Configuration["AzureAd:Authority"];
51+
jwtOptions.Audience = Configuration["AzureAd:Audience"];
52+
})
53+
.AddPolicyScheme(Consts.MY_POLICY_SCHEME, displayName: null, options =>
54+
{
55+
options.ForwardDefaultSelector = context =>
56+
{
57+
string authorization = context.Request.Headers[HeaderNames.Authorization];
58+
if (!string.IsNullOrEmpty(authorization) && authorization.StartsWith("Bearer "))
59+
{
60+
var token = authorization.Substring("Bearer ".Length).Trim();
61+
var jwtHandler = new JsonWebTokenHandler();
62+
63+
if(jwtHandler.CanReadToken(token)) // it's a self contained access token and not encrypted
64+
{
65+
var issuer = jwtHandler.ReadJsonWebToken(token).Issuer; //.Equals("B2C-Authority"))
66+
if (issuer == Consts.MY_THIRD_PARTY_ISS) // Third party identity provider
67+
{
68+
return Consts.MY_THIRD_PARTY_SCHEME;
69+
}
70+
71+
if (issuer == Consts.MY_AAD_ISS) // AAD
72+
{
73+
return Consts.MY_AAD_SCHEME;
74+
}
75+
}
76+
}
77+
78+
// We don't know with it is
79+
return Consts.MY_AAD_SCHEME;
80+
};
81+
});
82+
```
83+
2484
## Examples
2585

2686
The following example shows a higher level scheme that combines lower level schemes. Google authentication is used for challenges, and cookie authentication is used for everything else:

aspnetcore/toc.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1575,6 +1575,8 @@ items:
15751575
uid: security/authentication/cookie
15761576
- name: Configure OIDC web authentication
15771577
uid: security/authentication/configure-oidc-web-authentication
1578+
- name: Configure JWT bearer authentication
1579+
uid: security/authentication/configure-jwt-bearer-authentication
15781580
- name: Configure certificate authentication
15791581
uid: security/authentication/certauth
15801582
- name: Configure Windows authentication

0 commit comments

Comments
 (0)