json web token is a access token.
It's also known as jot.
When a JWT is signed, it becomes a JWS and can be used for sender authentication and authorization.
The main purpose of JWTs is to transfer claims (ie identity property) between two parties
This is a simple, optionally validated and/or encrypted, container format.
Because the token is signed and contains property, it is not necessary for the recipient to call a server to validate the token or obtain additional information.
The data format is JSON.
JWTs, like any other client-side data, can be stored as cookies
JWT is constructed from three different parts:
Encoded, JWT is a compact, printable representation of data, along with a signature to verify its authenticity (and therefore perform authentication)
These three parts are encoded separately and a JWT encoded looks like:
Header.Payload.Signature
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.
TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
where:
{
"alg": "HS256",
"typ": "JWT"
"kid": "5c6097630863e16d9eb72adf2c6f4624aeb1f6aa"
}
where:
Note Keys are opened and public thanks to the discovery endpoints.
For instance, on openId:
ie user data
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
where the property are known as claims
Claims are just the JSON properties of the payload
There are three types of claims:
JWTs carry certain common fields known as standard claims such as:
If a token is signed and contains standard-based claims, other services can consume them as service-to-service credentials.
See:
signature to verify the identify and the payload integrity.
When a JWT is signed, it becomes a JWS (rfc7515)
Example with HMAC SHA256 hashing algorithm if defined in the header
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
JWS can be used for sender authentication because it's signed. A JSON Web Token will be returned when a user successfully logs in using their credentials.
It can be sent:
Whenever the user wants to access a protected route, it should send the JWT Therefore the content of the header should look like the following.
Authorization: Bearer <token>
The server’s protected routes will check for a valid JWT in the Authorization header; if there is, the user will be allowed.
As JWTs are self-contained, all the necessary information is there, reducing the need of going back and forward to the database.
signing them, using JSON Web Signatures (JWS,RFC 75156),
The default signature method for JWT’s is known as HS256. HS stands in this case for HMAC Signature using SHA256.
RS256 (RSA Signature with SHA-256) is an private/public key algorithm (ie asymmetric)
Multiple keys can be found in the JWKS when rotating signing certificates.
HS256 (HMAC with SHA-256) is a symmetric algorithm. This private key (or secret) is created when the application is registered.
Encrypting them, using JSON Web Encryption (JWE, RFC 75167).
The frontend does not check the signature, it simply decodes the JWT so it can display its contents.
The actual checks are performed by the backend where all JWTs are verified (ie the token is decoded and the signature is verified)
You can debug at http://jwt.io/.
Example with express code: When items are added, the backend constructs a new JWT with the new item in it and a new signature
function cartValidator(req, res, next) {
if(!req.cookies.cart) {
req.cart = { items: [] };
} else {
try {
req.cart = {
items: jwt.verify(req.cookies.cart, process.env.AUTH0_CART_SECRET, cartVerifyJwtOptions).items
};
} catch(e) {
req.cart = { items: [] };
}
}
next();
}
Decoding is extracting the payload.
function populateCart() {
const cartElem = $('#cart');
cartElem.empty();
const cartToken = Cookies.get('cart');
if(!cartToken) {
return;
}
const cart = jwt_decode(cartToken).items;
cart.forEach(itemId => {
const name = items.find(item => item.id == itemId).name;
cartElem.append(`<li>${name}</li>`);
});
}
function parseJwt (token) {
var base64Url = token.split('.')[1];
var base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
var jsonPayload = decodeURIComponent(atob(base64).split('').map(function(c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));
return JSON.parse(jsonPayload);
};
Because the signature is encoded separately, it is possible to remove the signature and then change the header to claim the JWT is unsigned.
If the application consider unsigned JWTs valid, an attacker may modify the payload (for instance, to set the user role to root).
Be sure to consider valid only signed JWT.