Okay, so this is a rather different way of learning about JWTs. But I think, if done right it can teach more effectively than a long blog post filled with thousands of words. So, let's begin.
JWT or JSON Web Token is structured token format of encoding JSON data in a way that can be cryptographically verified.
Notice the dots? If you "split" at dots you get 3 strings that make up the JWT.
JWT = headerString.payloadString.signatureString
(or signature, doesn't matter in this case)
headerString = base64(header)
payloadString = base64(payload)
They are just base64 encodings for header & payload (header is a JSON object with metadata (type of JWT) & payload is another object with user-defined data with some standard keys).
Note: Here base64() implies base64URL(), assume them as functions that encode the object to base64 form, the later encodes it in URL-friendly manner. Similar assumptions ahead.
To keep things less repetitive ahead, let:
headerPayloadString = headerString.payloadString
We can form JWTs in different ways, for educational purpose lets look at a simple one (but not used IRL as much).
The signatureString/signature is discussed in following approach sections (sha256Signature, rsa256Signature).
SHA is a hashing algorithm. As mentioned this approach not used IRL as much given it's drawbacks discussed later.
sha256Signature = sha256(headerPayloadString , 'sharedSecret')
sha256JWT = headerPayloadString.sha256Signature
- Calculate signature as
sha256(headerPayloadString , 'sharedSecret')
- If both the input signature and calculated signature match, the JWT is valid.
Notice how we need to use the same
sharedSecret or "key" for creating/signing & verifying? That means if we use an authentication server we have to share the same key between the server and the consumer/application. This leads to security concerns.
RSA is public key encryption algorithm, consisting of 2 keys a private and public key (pair).
sha256XSignature = sha256(headerPayloadString)
We don't use a key here (non-HMAC way)
rsa256Signature = rsa256Encrypt(sha256XSignature, 'privateKey')
rsaJWT = headerPayloadString.rsa256Signature
- Take the headerPayloadString, and hash everything with SHA-256
- Decrypt (rsa256Decrypt) the JWT using the public key, and obtain the rsa256Signature
- Compare the received JWT signature with the calculated one, if they match, the JWT is valid.
Voila! You now know the basic mechanics of JWTs. I recommended researching a bit more to supplement this post with. Hope, this helped clear some doubts.