Last active
June 15, 2024 04:41
-
-
Save dj-nitehawk/220363f14e649a2cb850d61f9bd793b5 to your computer and use it in GitHub Desktop.
Dynamic claim/permission hydration instead of embedding everything in JWT Token
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
sealed class UserPermissionHydrator(UserPermissionService userPermissionService) : IClaimsTransformation | |
{ | |
public async Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal) | |
{ | |
var userId = principal.Claims.FirstOrDefault(c => c.Type == "UserId")?.Value; | |
ArgumentNullException.ThrowIfNull(userId); | |
var userPermissions = await userPermissionService.GetPermissionsForUser(userId); | |
if (userPermissions.Length != 0) | |
principal.AddIdentity(new(userPermissions.Select(p => new Claim("permissions", p)))); | |
return principal; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
sealed class LoginEndpoint : EndpointWithoutRequest | |
{ | |
public override void Configure() | |
{ | |
Get("login"); | |
AllowAnonymous(); | |
} | |
public override Task HandleAsync(CancellationToken c) | |
{ | |
var jwtToken = JwtBearer.CreateToken( | |
o => | |
{ | |
o.SigningKey = "JWT_Signing_Secret_Of_At_Least_32_Characters"; | |
o.User.Claims.Add(("UserId", "USR001")); //embed just the user id claim | |
}); | |
return SendAsync(jwtToken); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Security.Claims; | |
using FastEndpoints; | |
using FastEndpoints.Security; | |
using FastEndpoints.Swagger; | |
using Microsoft.AspNetCore.Authentication; | |
var bld = WebApplication.CreateBuilder(args); | |
bld.Services | |
.AddTransient<UserPermissionService>() //register the user permission service | |
.AddTransient<IClaimsTransformation, UserPermissionHydrator>() //register the claim transformation | |
.AddAuthenticationJwtBearer(s => s.SigningKey = "JWT_Signing_Secret_Of_At_Least_32_Characters") | |
.AddAuthorization() | |
.AddFastEndpoints() | |
.SwaggerDocument(); | |
var app = bld.Build(); | |
app.UseAuthentication() | |
.UseAuthorization() | |
.UseFastEndpoints() | |
.UseSwaggerGen(); | |
app.Run(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
sealed class ProtectedEndpoint : EndpointWithoutRequest | |
{ | |
public override void Configure() | |
{ | |
Get("protected"); | |
Permissions("Do_Some_Thing"); | |
} | |
public override Task HandleAsync(CancellationToken c) | |
=> SendAsync("You are authorized!"); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
sealed class UserPermissionService | |
{ | |
public Task<string[]> GetPermissionsForUser(string userId) | |
//fetch the user's permissions from a db or cache here | |
=> Task.FromResult( | |
userId == "USR001" | |
? ["Do_Some_Thing", "Do_Another_Thing"] | |
: Array.Empty<string>()); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@gabriel-rodriguezcastellini
not possible.
IClaimsTransformation
is part of the asp.net auth middleware and it gets executed way before pre-processors run. pre-processors only run after the user is authenticated and it's too late in the pipeline to populate permissions for the user.