Guide to JWTs for Beginners
A JWT is a structured security token format used to encode JSON data. The main reason to use JWT is to exchange JSON data in a way that can be cryptographically verified.
Join the DZone community and get the full member experience.Join For Free
What Is a JWT?
A JWT is a structured security token format used to encode JSON data. The main reason to use JWT is to exchange JSON data in a way that can be cryptographically verified. There are two types of JWTs:
JSON Web Signature (JWS)
JSON Web Encryption (JWE)
The data in a JWS is public—meaning anyone with the token can read the data—whereas a JWE is encrypted and private. To read data contained within a JWE, you need both the token and a secret key.
When you use a JWT, it’s usually a JWS. The 'S' (the signature) is the important part and allows the token to be validated. For the rest of this post, I will talk about the JWS format and walk through decoding an example JWT.
How JWTs Are Used
OAuth 2.0 identity providers (IdP) commonly use JWTs for access tokens. You may have seen an HTTP request with an authorization header that looks like this:
Using a JWT (actually a JWS) allows the token to be validated locally, without making an HTTP request back to the IdP, thereby increasing your application’s performance. Applications can make use of data inside the token, further reducing expensive HTTP calls and database lookups.
A JWS (the most common type of JWT) contains three parts separated by a dot (
.). The first two parts (the "header" and "payload") are Base64-URL encoded JSON, and the third is a cryptographic signature.
Let’s look at an example JWT:
Breaking this down into the individual sections we have:
Next, each of the first two sections are base64-url decoded:
The last section in the JWT, the signature, is also base64-url encoded, but it’s just binary data; if you try to decode it, you will end up with non-displayable characters:
You can use a tool like
hexdump to view the signatures content:
Once you start using JWTs you start hearing the word "claim" everywhere. A JWT claim is a key/value pair in a JSON object. In the example above,
"name": "Joe Coder", the claim key is
name and the value is
Joe Coder. The value of a claim can be any JSON object.
There are three types of claims: "registered," "public," and "private." You can find the list of registered and public claims in the official IANA Registry. You can also add any other custom claim to a JWT; these are known as "private claims."
The use of registered claims is optional, but when they are present, they MUST be validated. For example, a JWT may contain date-time fields that describe when the token is valid.
- Issued At (
iat) - The time the JWT was created
- Expiration Time (
exp) - The time at which the JWT is no longer valid
- Not Before (
nfb) - The earliest time the JWT would be valid
The header of a JWT contains information about how the token was created. In my example, the "algorithm" (
alg) claim is set to
HS256, which specifies the hashing algorithm HMAC SHA-256 is used to generate or validate the signature.
The JWT specifications list a few different signing algorithms; each of these algorithms works slightly different. For simplicity’s sake, there are two types of algorithms: - HMAC based shared secret, these all start with the prefix
HS, which stands for HMAC SHA) - Public key pair (either RSA or ECDSA keys)
The JWT in this example (actually a JWS, remember the 'S' stands for "signature") uses the
HS256 algorithm. To validate the JWS, calculate the HMAC of the first two parts of the token, then compare the output with the base64-url decoded signature.
On the command line, you can use
openssl to check the signature:
If the output matches the original signature block, the signature is valid.
Problems With JWTs
Fully validating a JWT is MUCH more complex than running a couple CLI commands. There are many edge cases and exploits; you should ALWAYS use a trusted JWT library and keep it up to date.
Visit token.dev to debug JWTs from within your browser!
One of the biggest problems with the JWT, is the signature verification to be disabled by setting the algorithm header claim to
none. Many JWT library vulnerabilities have been related to the
When base64-url decoded this JWT contains the same information as the original example (minus the signature):
There is nothing secure about this example because it’s missing the signature; it cannot be cryptographically verified.
Learn More About JWT
When used correctly, JWT can help with both authorization and transferring data between two parties. As with all security topics, it’s not a generic solution; deciding to use JWTs is often a security vs. performance trade-off. Validating a token locally does NOT check if it has been revoked, e.g., a user has logged out or has been deleted. Keeping the life span of the token short (by setting the "expiration" claim) can help mitigate the risk.
Learn more about JWTs and building secure applications with these links:
If you enjoyed this blog post and want to see more like it, follow @oktadev on Twitter, subscribe to our YouTube channel, or follow us on LinkedIn. As always, please leave your questions and comments below— we love to hear from you!
Published at DZone with permission of Brian Demers, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.