Once we have a list of claims, or assertions, written inside the token, we must sign it. This is because anyone can create a token with those claims, or even tokens with different claims! We don't want to honor these tokens; we only want to honor tokens that are generated by our own servers (are authentic) and have not been tampered with (have integrity). We can do this by first attaching a JWS signature to the token, and then validating it when the token is processed.
The supported algorithms for signing tokens are defined in the JSON Web Algorithms (JWA) specification. Generally, there are two types of algorithms used for signing a token:
- Asymmetrically, using a pair of public/private keys (for example, RS256, RS384, and RS512)
- Symmetrically, using a secret (for example, HS256, HS384, and HS512)
Regardless of which algorithm is chosen, the base-64 encoded header and payload are first concatenated together, separated by a period (.). This combined string ([base64Header].[base64Payload]) is then passed into the algorithm to generate the JWS signature:
const header = {
alg: [algorithm],
typ: "JWT"
}
const payload = {
admin: true
}
const base64Header = btoa(header);
const base64Payload = btoa(payload);
const jwsSignature = alg(`${base64Header}.${base64Payload}`, [k])
Here, k is the secret or private key required for the algorithm. This is always kept private.
This JWS signature is then concatenated to the end of the header/payload to generate the complete JWT, which has the format [base64Header].[base64Payload].[base64JwsSignature].
When our server receives this JWT, it will regenerate a new JWS signature from the header and payload values, as well as the secret key, and compare it with the signature attached to the token. If there is a match, then our server can be confident that whoever produced the token had access to our secret key. Since our key is secret, then our server can be confident that we are the ones that issued the token, and can trust the claims made by the token. However, if there is a mismatch, it means that the token has either been signed with a different key, or has been tampered with, and should not be trusted.
Now, we understand why we need to sign the token (to ensure authenticity and integrity), so let's take a look at the difference between the two types of signing algorithms.