How JWT enables password-less authentication
In this blog, we will learn about JWT and how it helps with password-less authentication. If you haven’t already, check out my previous article The technology behind the smoothest sign-in process | OAuth2.0 and OIDC in the series.
Sign in with Google
In the last article, we discussed how sign in with Google works. Steve — our developer has built a ToDo App. Bob is a user of the App and he uses his Google account to sign in to the ToDo App.
The flow between different entities is shown below.
What is the token that Google provided to Bob, and later ToDo UI sent to ToDo App? It’s JWT — Json Web Tokens. And before we dive into the technicality of JWT, let’s understand this from a different angle.
Essentially Google is sending an identification certificate back to Bob, which could be something like this:
To whoever it may concern,
I have verified the identity of Bob. This document certifies that his is Bob@gmail.com. This certificate is valid till 7th Jan, 2024 2:00 PM.
Signed by
Google.
Signature of the Google.
The above certificate states that whoever presents that certificate is Bob. Google has verified his identity and has signed this certificate. Bob can take this certificate to any app that supports sign-in with Google.
So whichever app reads this certificate needs to ensure two things
- This is signed by Google
- The content is not modified.
If the above two things are verified, then the app can say for sure that the presenter of this certificate is indeed Bob.
And that’s what the ToDo App does with the JWT. JWT is nothing but a digitally signed certificate from Google verifying the identity of user Bob.
Encryption
Encryption means translating the original message to an alternate form known as ciphertext. Encryption can be used for two different use cases:
- Encrypt the original message so no one else can read it, and only an authorized party can decrypt it.
- Create a digital signature. To verify that a trusted party has created this message, and the message is not tempered.
Encryption using asymmetric key pair
In the asymmetric Encryption, there are two keys involved. Public key and private key.
Public key
Used to encrypt messages or check the legitimacy of a digital signature. Anyone in a group can access a public key.
Private key
Used to decrypt messages created with a public key, or to create signatures. Only the owner of the private key knows it.
Here we are interested in the second use case — Creating a digital signature. To verify that a trusted party has created this message, and the message is not tempered.
Digital signature
The sender’s private key encrypts the data, which is the digital signature. The receiver uses the public key to decrypt the data and verify that it matches the attachment.
Example of digital signature
Charlie sends a text to Alice. Alice wants to verify that the text is indeed sent by Charlie and that no one else has tempered with the text.
Sender (Charlie)
Charlie has a message. He encrypts it using his private key. That generates a signature. Send the original text message and signature to Alice.
signature = encrypt(message, privateKey)
Receiver (Alice)
Receives a message and a signature. Decrypt the signature using Charlie’s public key. Verify that the decrypted message matches with the original message.
decryptedMessage = decrypt(signature, publicKey)
assert(decryptedMessage === message)
If they match, the signature is considered valid. If they don’t match, it either means that a different key was used to encrypt it, or that the message has been altered (either intentionally or unintentionally).
Coming back to the original problem…
Comparing our original use case of signing in with Google to the above example
- Google is the Charlie
- Bob’s identification certificate from Google (JWT) is the Message
- ToDo App is the Alice
Structure of JWT
In its compact form, JSON Web Tokens consist of three parts separated by dots (.
), which are:
- Header
- Payload
- Signature
Therefore, a JWT typically looks like the following.
xxxxx.yyyyy.zzzzz
Header
The header typically consists of two parts: the type of the token, which is JWT, and the encryption algorithm being used, such as HMAC SHA256 or RSA.
For example:
{
"alg": "RSA",
"typ": "JWT"
}
This is equivalent to Google saying
This certificate is of type JWT and singed using RSA algorithm
Payload
The second part of the token is the payload, which contains the claims. Claims are statements about an entity (typically, the user) and additional data. There are three types of claims: registered, public, and private claims.
I have verified the identity of Bob. This document certifies that his is Bob@gmail.com. This certificate is valid till 7th Jan, 2024 2:00 PM.
The above claims from Google may look like this
{
"name": "Bob",
"email": "Bob@gmail.com"
"exp": "7th Jan, 2024 2:00 PM"
}
Signature
As we saw before, a signature is created by encrypting the message. Here the encryption is done using the RSA algorithm with the private key of Google. Note: Only Google can have its private key, as the name suggests.
signature = encrypt(message, privateKey)
In the case of JWT, the message is a Base64 encoded header JSON and Base64 encoded payload JSON, joined by '.' (dot)
message = base64(header) + "." + base64(payload)
After Google encrypts the text, it generates the signature.
signature = encrypt(message, private key)
Join together base64 header, base64 payload, and signature by "." and that becomes JWT.
jwt = base64(header) + "." + base64(payload) + "." + signature
Verify JWT
To verify a digital signature, the ToDo App will
Parse message and signature from JWT
base64Header, base64Payload, signature = parse(jwt)
message = base64Header + "." + base64Payload
Decrypts the digital signature using the sender’s PUBLIC key, and
decryptedMessage = decrypt(text, publicKey)
Compares two messages
assert(message === decryptedMessage)
If they match, the signature is considered valid. If they don’t match, it either means that a different key was used to encrypt it, or that the data has been altered (either intentionally or unintentionally).
I hope this blog helps you with learning about JWT. If you like the blog, don’t forget to hit the Clap (👏) button. If you like to learn more about it, check out the references below.
References
- RFC for JWT: https://datatracker.ietf.org/doc/html/rfc7519
- Digital signature video from Computerphile: https://youtu.be/s22eJ1eVLTU?si=X_zJKUiemKspcx8B
- https://jwt.io/introduction
- https://stackoverflow.com/questions/18257185/how-does-a-public-key-verify-a-signature