Skip to content

Instantly share code, notes, and snippets.

@ddjerqq
Last active April 3, 2025 10:32
Show Gist options
  • Save ddjerqq/d2c378e14f5b6f28ba8df2287547aee5 to your computer and use it in GitHub Desktop.
Save ddjerqq/d2c378e14f5b6f28ba8df2287547aee5 to your computer and use it in GitHub Desktop.
dotnet JWT generator using an RSA encrypted private key
public static class JwtGenerator
{
public const string TokenName = "authorization";
public static readonly string ClaimsIssuer = "JWT__ISSUER".FromEnvRequired();
public static readonly string ClaimsAudience = "JWT__AUDIENCE".FromEnvRequired();
private static readonly string Key = "JWT__KEY".FromEnvRequired();
private static readonly string KeyPath = "JWT__KEY_PATH".FromEnvRequired();
/// <summary>
/// These events ensure we can read the authorization from cookies, auery or headers. <br/>
/// The priorities are: query > header > cookie.<br/>
/// </summary>
public static readonly JwtBearerEvents Events = new()
{
OnMessageReceived = ctx =>
{
ctx.Request.Query.TryGetValue(TokenName, out var query);
ctx.Request.Headers.TryGetValue(TokenName, out var header);
ctx.Request.Cookies.TryGetValue(TokenName, out var cookie);
ctx.Token = (string?)query ?? (string?)header ?? cookie;
return Task.CompletedTask;
},
};
private static readonly JwtSecurityTokenHandler Handler = new();
private static readonly SigningCredentials SigningCredentials;
public static readonly TokenValidationParameters TokenValidationParameters;
/// <summary>
/// Static constructor ensures that we load the key file and decrypt it using the provided env variables.
/// </summary>
static JwtGenerator()
{
var key = RSA.Create();
var keyBytes = File.ReadAllBytes(KeyPath);
key.ImportFromEncryptedPem(Encoding.UTF8.GetString(keyBytes), Encoding.UTF8.GetBytes(Key));
var securityKey = new RsaSecurityKey(key);
SigningCredentials = new SigningCredentials(securityKey, SecurityAlgorithms.RsaSha256Signature);
TokenValidationParameters = new TokenValidationParameters
{
ValidIssuer = ClaimsIssuer,
ValidAudience = ClaimsAudience,
IssuerSigningKey = securityKey,
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidAlgorithms = [SecurityAlgorithms.RsaSha256Signature],
};
}
/// <summary>
/// Generates a JWT token with the provided claims and expiration time.
/// </summary>
public static string GenerateToken(IEnumerable<Claim> claims, TimeSpan expiration)
{
var token = new JwtSecurityToken(
ClaimsIssuer,
ClaimsAudience,
claims,
expires: DateTime.UtcNow.Add(expiration),
signingCredentials: SigningCredentials);
return Handler.WriteToken(token);
}
}
public static class StringExt
{
public static string FromEnvRequired(this string key) =>
Environment.GetEnvironmentVariable(key)
?? throw new InvalidOperationException($"{key} is not set in the environment");
}
@ddjerqq
Copy link
Author

ddjerqq commented Apr 3, 2025

.env.example

JWT__ISSUER=localhost
JWT__AUDIENCE=localhost
JWT__KEY=ENCRYPTIONKEY
JWT__KEY_PATH=/path/to/jwt.key

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment