I'm trying to use JWT tokens. I managed to generate a valid JWTTokenString
and validated it on the JWT debugger but I'm having an impossible time validating the token in .Net. Here's the code I have so far:
class Program {
static string key = "401b09eab3c013d4ca54922bb802bec8fd5318192b0a75f201d8b3727429090fb337591abd3e44453b954555b7a0812e1081c39b740293f765eae731f5a65ed1";
static void Main(string[] args) {
var stringToken = GenerateToken();
ValidateToken(stringToken);
}
private static string GenerateToken() {
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key));
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
var header = new JwtHeader(credentials);
var payload = new JwtPayload {
{ "some ", "hello "},
{ "scope", "world"},
};
var secToken = new JwtSecurityToken(header, payload);
var handler = new JwtSecurityTokenHandler();
return handler.WriteToken(secToken);
}
private static bool ValidateToken(string authToken) {
var tokenHandler = new JwtSecurityTokenHandler();
var validationParameters = GetValidationParameters();
SecurityToken validatedToken;
IPrincipal principal = tokenHandler.ValidateToken(authToken, validationParameters, out validatedToken);
Thread.CurrentPrincipal = principal;
return true;
}
private static TokenValidationParameters GetValidationParameters() {
return new TokenValidationParameters() {
//NOT A CLUE WHAT TO PLACE HERE
};
}
}
All I want is a function that receives a token and returns true or false based on its validity. From research I've seen people use IssuerSigningToken
to assign the validation key. But when I try to use it, it doesn't seem to exist. Could anyone give me a hand on validating the token?
You must use the same key to validate the token as the one you use to generate it. Also you need to disable some validations such as expiration, issuer and audiance, because the token you generate doesn't have these information (or you can add these information). Here's a working example:
class Program
{
static string key = "401b09eab3c013d4ca54922bb802bec8fd5318192b0a75f201d8b3727429090fb337591abd3e44453b954555b7a0812e1081c39b740293f765eae731f5a65ed1";
static void Main(string[] args)
{
var stringToken = GenerateToken();
ValidateToken(stringToken);
}
private static string GenerateToken()
{
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key));
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
var secToken = new JwtSecurityToken(
signingCredentials: credentials,
issuer: "Sample",
audience: "Sample",
claims: new[]
{
new Claim(JwtRegisteredClaimNames.Sub, "meziantou")
},
expires: DateTime.UtcNow.AddDays(1));
var handler = new JwtSecurityTokenHandler();
return handler.WriteToken(secToken);
}
private static bool ValidateToken(string authToken)
{
var tokenHandler = new JwtSecurityTokenHandler();
var validationParameters = GetValidationParameters();
SecurityToken validatedToken;
IPrincipal principal = tokenHandler.ValidateToken(authToken, validationParameters, out validatedToken);
return true;
}
private static TokenValidationParameters GetValidationParameters()
{
return new TokenValidationParameters()
{
ValidateLifetime = false, // Because there is no expiration in the generated token
ValidateAudience = false, // Because there is no audiance in the generated token
ValidateIssuer = false, // Because there is no issuer in the generated token
ValidIssuer = "Sample",
ValidAudience = "Sample",
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key)) // The same key as the one that generate the token
};
}
}
In my case I only want to validate if the signature is correct. Most likely you will probably want to use @meziantou answer. But if you only want to verify that the message has not been tampered with here is an example. Lastly since I am the only person generating this tokens and I know I will be generating them using HmacSha256 I am using this approach.
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Text;
class Program
{
static readonly byte[] key = Encoding.UTF8.GetBytes("f645b33ef0d04cbe859777ac6f46226d");
// use this algorithm for example to work
static readonly string securityAlgorithm = SecurityAlgorithms.HmacSha256;
static void Main()
{
var token = GenerateToken();
var isTokenValid = IsJwtTokenValid(token);
if (isTokenValid)
Console.WriteLine(true);
}
/// <summary>
/// This method assumes token has been hashed using HMACSHA256 algorithm!
/// </summary>
private static bool IsJwtTokenValid(string token)
{
// example of token:
// header payload signature
// eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJmb29AZ21haWwuY29tIiwiZXhwIjoxNjQ1NzM1MDU2fQ.Gtrm2G_35ynyNd1-CjZ1HsvvFFItEsXPvwhaOsN81HQ
// from JWT spec
static string Base64UrlEncode(byte[] input)
{
var output = Convert.ToBase64String(input);
output = output.Split('=')[0]; // Remove any trailing '='s
output = output.Replace('+', '-'); // 62nd char of encoding
output = output.Replace('/', '_'); // 63rd char of encoding
return output;
}
try
{
// position of second period in order to split header+payload and signature
int index = token.IndexOf('.', token.IndexOf('.') + 1);
// Example: Gtrm2G_35ynyNd1-CjZ1HsvvFFItEsXPvwhaOsN81HQ
string signature = token[(index + 1)..];
// Bytes of header + payload
// In other words bytes of: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJmb29AZ21haWwuY29tIiwiZXhwIjoxNjQ1NzM1MDU2fQ
byte[] bytesToSign = Encoding.UTF8.GetBytes(token[..index]);
// compute hash
var hash = new HMACSHA256(key).ComputeHash(bytesToSign);
var computedSignature = Base64UrlEncode(hash);
// make sure that signatures match
return computedSignature.Length == signature.Length
&& computedSignature.SequenceEqual(signature);
}
catch
{
return false;
}
}
private static string GenerateToken()
{
var securityKey = new SymmetricSecurityKey(key);
var credentials = new SigningCredentials(securityKey, securityAlgorithm);
var secToken = new JwtSecurityToken(
signingCredentials: credentials,
claims: new[]
{
new Claim(JwtRegisteredClaimNames.Sub, "[email protected]")
},
expires: DateTime.UtcNow.AddDays(1));
var handler = new JwtSecurityTokenHandler();
return handler.WriteToken(secToken);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With