JSON Web Tokens (JWT) are a compact, URL-safe means of representing claims to be transferred between two parties. By employing digital signatures, JWTs ensure that data remains tamper-proof during transit.
Structure of a JWT
A JWT is composed of three distinct segments separated by periods:
- Header: Specifies the algorithm and token type.
- Payload: Contains the actual claims or data. Note that since this is Base64 encoded, sensitive information must never be included here.
- Signature: Generated by hashing the header, payload, and a secret key. This component verifies the integrity of the token and authenticates the sender.
Implementation in .NET
To implement JWT in a .NET environment, the JWT package is commonly used. Below is an example of how to generate a token:
var claimData = new Dictionary<string, object>
{
{ "uid", 999 },
{ "role", "administrator" }
};
var secureKey = "Your-Unique-Secret-Key";
IJwtAlgorithm hashAlgo = new HMACSHA256Algorithm();
IJsonSerializer jsonSerializer = new JsonNetSerializer();
IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
IJwtEncoder jwtEncoder = new JwtEncoder(hashAlgo, jsonSerializer, urlEncoder);
string generatedToken = jwtEncoder.Encode(claimData, secureKey);
Token Decoding and Verification
To decode and validate an incoming token, the service must provide the original secret key. If the signature does not match or the token has been altered, validation will fail.
string incomingToken = "header.payload.signature";
string secret = "Your-Unique-Secret-Key";
try
{
IJwtDecoder decoder = new JwtDecoder(new JsonNetSerializer(), new JwtValidator(new JsonNetSerializer(), new UtcDateTimeProvider()), new JwtBase64UrlEncoder());
var decodedJson = decoder.Decode(incomingToken, secret, verify: true);
}
catch (TokenExpiredException)
{
// Handle expired token
}
catch (SignatureVerificationException)
{
// Handle tampering detection
}
Managing Expiration
To prevent replay attacks, tokens should have a limited lifespan. You can define an expiration claim (exp) within the payload, representing the Unix timestamp after which the token is no longer valid:
// Calculate expiration: current time + 60 seconds
double expiration = (DateTime.UtcNow.AddSeconds(60) - new DateTime(1970, 1, 1)).TotalSeconds;
claimData.Add("exp", expiration);
The library automatically evaluates the exp field during the decoding prrocess. If the current time exceeds this value, the validator will trigger an exception, ensuring the token is rejected.