'How to validate a JWT token
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?
Solution 1:[1]
Validate Token in Jwt Middleware Class that Invoke Method fire in every request for Authorization
JwtMiddleware
{
private readonly RequestDelegate _next;
private readonly TokenValidationParameters _tokenValidationParams;
public JwtMiddleware(RequestDelegate next, TokenValidationParameters
tokenValidationParams)
{
_next = next;
_tokenValidationParams = tokenValidationParams;
}
public async Task Invoke(HttpContext context)
{
try{
var token = context.Request.Headers["Authorization"].FirstOrDefault()?.Split(" ").Last();
var jwtTokenHandler = new JwtSecurityTokenHandler();
// Validation 1 - Validation JWT token format
var tokenInVerification = jwtTokenHandler.ValidateToken(token, _tokenValidationParams, out var validatedToken);
if (validatedToken is JwtSecurityToken jwtSecurityToken)
{
var result = jwtSecurityToken.Header.Alg.Equals(SecurityAlgorithms.HmacSha256, StringComparison.InvariantCultureIgnoreCase);
if (result == false)
{
Error Invalid = new Error()
{
Success = false,
Errors = "Token is Invalid"
};
context.Items["Error"] = Invalid;
}
}
}
catch (Exception ex)
{
Error Invalid = new Error()
{
Success = false,
Errors = "Token does not match or may expired."
};
context.Items["Error"] = Invalid ; // userService.GetById(userId);
}
await _next(context);
}
}
Solution 2:[2]
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);
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Md. Nazmul Nadim |
| Solution 2 | Tono Nam |
