Skip to content

Instantly share code, notes, and snippets.

@VictorKoenders
Last active November 29, 2023 11:03
Show Gist options
  • Save VictorKoenders/dfee47750d23e9636ff218cb8cee424e to your computer and use it in GitHub Desktop.
Save VictorKoenders/dfee47750d23e9636ff218cb8cee424e to your computer and use it in GitHub Desktop.
JWT helper function for encoding/decoding + validating JWT tokens
public static class JwtHelper
{
static ECDsa? ECDsaKey { get; set; }
public static string InitializeWithRandomKey()
{
ECDsaKey = ECDsa.Create(ECCurve.CreateFromFriendlyName("nistP521"));
return StringKey;
}
public static string ExportPublicKey() => Convert.ToBase64String(ECDsaKey!.ExportSubjectPublicKeyInfo());
public static string StringKey
{
get
{
var key = ECDsaKey ?? throw new Exception("JwtHelper.Key not initialized");
var p = key.ExportParameters(true);
var ret = p.Curve.Oid.FriendlyName;
ret += ":" + Convert.ToBase64String(p.D);
ret += ":" + Convert.ToBase64String(p.Q.X);
ret += ":" + Convert.ToBase64String(p.Q.Y);
return ret;
}
set
{
var parts = value.Split(':');
if (parts.Length != 4) throw new Exception("Invalid key");
var parameters = new ECParameters
{
Curve = ECCurve.CreateFromFriendlyName(parts[0]),
D = Convert.FromBase64String(parts[1]),
Q = new ECPoint
{
X = Convert.FromBase64String(parts[2]),
Y = Convert.FromBase64String(parts[3])
}
};
ECDsaKey = ECDsa.Create(parameters);
}
}
public static string GenerateJWT(JwtProperties props)
{
var claims = new[] {
new Claim("sub", props.UserEmail),
new Claim("jti", props.LicenseId.ToString()),
};
var key = new ECDsaSecurityKey(ECDsaKey ?? throw new Exception("JwtHelper.Key not initialized"));
var creds = new SigningCredentials(key, SecurityAlgorithms.EcdsaSha256);
var token = new JwtSecurityToken(
issuer: props.Issuer,
audience: props.Audience.ToString(),
notBefore: DateTimeOffset.UtcNow.UtcDateTime,
expires: props.ExpirationTime.UtcDateTime,
claims: claims,
signingCredentials: creds
);
return new JwtSecurityTokenHandler().WriteToken(token);
}
public static JwtProperties? ParseJWT(
string jwt,
string validIssuer,
LicenseAudience expectedAudience
)
{
var key = new ECDsaSecurityKey(ECDsaKey ?? throw new Exception("JwtHelper.Key not initialized"));
var validationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = key,
ValidateIssuer = true,
ValidIssuer = validIssuer,
ValidateAudience = true,
ValidAudience = expectedAudience.ToString(),
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero // Optional: Set the clock skew if needed
};
new JwtSecurityTokenHandler().ValidateToken(jwt, validationParameters, out SecurityToken validatedToken);
JwtSecurityToken token = (JwtSecurityToken)validatedToken;
return new(
token.Issuer,
token.Subject,
expectedAudience,
token.ValidTo.ToUniversalTime(),
new Guid(token.Id)
);
}
}
public record JwtProperties(
string Issuer,
string UserEmail,
LicenseAudience Audience,
DateTimeOffset ExpirationTime,
Guid LicenseId
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment