When learning about JWTs, some terms you hear a lot are signatures and signing. If the tutorials are creating JWTs, you may see them select an algorithm to create the signature. But what are signing algorithms, and how do they work? Read further to learn the differences between the two most common algorithms, and which one is recommended to use in applications.
If you prefer, you can watch the video below with me explaining the differences between two JWT signing algorithms! 👇
What are JWT signatures?
When you create JSON Web Tokens, they are signed. Signing the token allows its recipient to validate that the content of the token wasn't changed and verify the original issuer of the token created signature.
Signing JWTs doesn't make their data unreadable. Signatures only verify that the content of the JWT was not changed.
The signature is the part of a JWT that verifies the content of the JWT hasn't changed since the moment it has been issued (as it would happen, for example, in bucket brigade attacks formerly known as "man or person in the middle" attacks).
RS256 and HS256 are the most common algorithms used for signing JWTs. This article will go over some differences between RS256 and HS256. This post will not cover the other JWT signing algorithms, such as ES256 or PS256.
To view more signing algorithims this link to the specs that lists all the signing algorithms.
How are JWT signatures crated?
Signatures are created by combining encoded versions of the header and payload of a JWT, passing them and the secret as parameters into the algorithm defined in the header.
The following is an example code that can be used to create a JWT signature.
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
The following is an example output of what the signed JWT looks like:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Each section(header, payload and signature) is separated by a period(.).
The following picture highlights the signature part of a JWT decoded via jwt.io:
JWTs are commonly signed using one of two algorithms: HS256 (HMAC using SHA256) and RS256 (RSA using SHA256).
That leaves you with the question:
What's the difference between RS256 and HS256 signing algorithms?
HS256 Signing Algorithm
HS256 (HMAC with SHA-256) is a symmetric keyed hashing algorithm that uses one secret key. Symmetric means two parties share the secret key. The key is used for both generating the signature and validating it.
Be mindful when using a shared key; it can open potential vulnerabilities if the verifiers(multiple applications) are not appropriately secured.
Read more about keyed hashes vs signatures on this stackexchange question
RS256 Signing Algorithm
RS256 (RSA Signature with SHA-256) is an asymmetric algorithm that uses a public/private key pair. The identity provider has a private key to generate the signature. The receiver of the JWT uses a public key to validate the JWT signature. The public key used to verify and the private key used to sign the token are linked since they are generated as a pair. Check out this blog post to get an introduction to Public-Key Cryptography
NOTE: In both cases, a third party could potentially find your secret key and generate a JWT that would be considered valid for your application. In the case of the HS256 algorithm, verifiers (applications) of tokens have the same key that signs a JWT, which increases the risk of being exposed to a third party. You would need to take caution to protect the key from being compromised, such as putting the secret in a secure store, limiting access to it, etc.
RS256 or HS256? Which Should You Use?
While both HS256 and RS256 can be used to verify the integrity of JWTs, the recommended algorithm at this time is RS256.
A signature must ensure authenticity, which means that the JWT content is the same as that generated by the sender. Both HS256 and RS256 algorithms ensure JWT authenticity.
RS256 also ensures non-repudiation, which means it guarantees that the sender has generated the signature.
With RS256, you are sure only the holder of the private key and no one else can sign tokens. In addition, if the secret key is compromised, you can rotate signing keys without re-deploying your application with a new secret, as you would have to do with HS256.
Keep in mind that regularly rotating keys is good even when keys aren't compromised. Rotating keys reduces the chance of a compromise. For example, Auth0 notifies you if you haven't rotated your key in more than 365 days.
You might be wondering if there is any scenario where you would choose HS256? Great question! And yes, there are a couple of situations where you may use HS256.
You could consider using HS256 when working on legacy applications that can't support RS256. Another possible use case for using HS256 instead of RS256 is when your application makes a very large number of requests because HS256 is more efficient than RS256.
Summary
In this article, you learned some key differences between the HS256 and RS256 signing algorithms for JWTs, which are as follows:
HS256 is a symmetric algorithm that shares one secret key between the identity provider and your application. The same key is used to sign a JWT and verify that signature.
RS256 algorithm is an asymmetric algorithm that uses a private key to sign a JWT and a public key to verify that signature.
RS256 is the recommended algorithm when signing your JWTs. It is more secure, and you can rotate keys quickly if they are compromised. (Auth0 signs JWTs with RS256 by default).
You can learn more about how signing keys work by reading the Auth0 docs.