Skip to content

Instantly share code, notes, and snippets.

@distantcam
Last active March 21, 2026 05:05
Show Gist options
  • Select an option

  • Save distantcam/f7ee8f6b91d74662b717f684e33955b5 to your computer and use it in GitHub Desktop.

Select an option

Save distantcam/f7ee8f6b91d74662b717f684e33955b5 to your computer and use it in GitHub Desktop.
AspNetCore Jwt Demo
#:sdk Microsoft.NET.Sdk.Web
#:package Microsoft.AspNetCore.Authentication.JwtBearer@10.*-*
#:property PublishAot=false
using System.Security.Claims;
using System.Text;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.JsonWebTokens;
using Microsoft.IdentityModel.Tokens;
var builder = WebApplication.CreateSlimBuilder(args);
builder.Configuration.AddInMemoryCollection(new Dictionary<string, string?>() {
{ "Jwt:Issuer", "SimpleLoginApp" },
{ "Jwt:Audience", "SimpleLoginApp" },
{ "Jwt:ExpirationInMinutes", "5" },
{ "Jwt:SecretKey", "IamTheVeryLongSecretKeyForValidatingJWTs" }
});
builder.Services.AddSingleton<JwtBlacklist>();
builder.Services
.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.TokenValidationParameters.ValidIssuer = builder.Configuration["Jwt:Issuer"];
options.TokenValidationParameters.ValidAudience = builder.Configuration["Jwt:Audience"];
options.TokenValidationParameters.IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(builder.Configuration["Jwt:SecretKey"]!));
});
builder.Services.AddAuthorization();
// ----------------------------------------------------------------------------
var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
app.Use(async (context, next) =>
{
if (context.User.Identity is not ClaimsIdentity { IsAuthenticated: true } identity)
{
await next(context);
return;
}
var blacklist = context.RequestServices.GetRequiredService<JwtBlacklist>();
var jti = identity.FindFirst(JwtRegisteredClaimNames.Jti)?.Value;
if (string.IsNullOrEmpty(jti) || blacklist.Contains(jti))
{
// Jwt is blacklisted from logout
context.Response.StatusCode = StatusCodes.Status401Unauthorized;
return;
}
await next(context);
});
// ----------------------------------------------------------------------------
app.MapPost("login",
(LoginRequest request, IConfiguration configuration) =>
{
// Checking valid user
if (request.Username != "SimpleUser" || request.Password != "SimplePassword01!")
{
return Results.Unauthorized();
}
var signingKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration["Jwt:SecretKey"]!));
var credentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256);
List<Claim> claims = [
new(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString("N")),
new(JwtRegisteredClaimNames.Sub, request.Username),
// other claims like roles and/or permissions
];
var tokenDescriptor = new SecurityTokenDescriptor
{
SigningCredentials = credentials,
Subject = new ClaimsIdentity(claims),
Expires = DateTime.UtcNow.AddMinutes(configuration.GetValue<int>("Jwt:ExpirationInMinutes")),
Issuer = configuration["Jwt:Issuer"],
Audience = configuration["Jwt:Audience"]
};
var tokenHandler = new JsonWebTokenHandler();
var accessToken = tokenHandler.CreateToken(tokenDescriptor);
return Results.Ok(new { accessToken });
});
app.MapPost("logout",
(ClaimsPrincipal claimsPrincipal, JwtBlacklist blacklist) =>
{
var jti = claimsPrincipal.FindFirst(JwtRegisteredClaimNames.Jti)?.Value;
if (string.IsNullOrEmpty(jti))
return Results.BadRequest();
blacklist.Add(jti);
return Results.Ok();
})
.RequireAuthorization();
app.MapGet("me",
(ClaimsPrincipal claimsPrincipal) => Results.Ok(claimsPrincipal.Claims.ToDictionary(c => c.Type, c => c.Value)))
.RequireAuthorization();
// ----------------------------------------------------------------------------
app.Run();
public record LoginRequest(string Username, string Password);
public class JwtBlacklist
{
private readonly List<string> _blacklist = [];
public void Add(string jwt) => _blacklist.Add(jwt);
public bool Contains(string jwt) => _blacklist.Contains(jwt);
}
@SimpleLoginApp_HostAddress = http://localhost:5000
POST {{SimpleLoginApp_HostAddress}}/login
Content-Type: application/json
{
"username": "SimpleUser",
"password": "BadLoginPassword"
}
###
# @name login
POST {{SimpleLoginApp_HostAddress}}/login
Content-Type: application/json
{
"username": "SimpleUser",
"password": "SimplePassword01!"
}
###
GET {{SimpleLoginApp_HostAddress}}/me
Authorization: Bearer {{login.response.body.$.accessToken}}
###
POST {{SimpleLoginApp_HostAddress}}/logout
Authorization: Bearer {{login.response.body.$.accessToken}}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment