RFC 7519: JWTs
Heya,
When building or implementing a CIAM (customer identity and access management) system, you'll probably encounter JSON Web Tokens (JWTs). Like many standards in the identity space, JWTs solve some problems well, but are not always appropriate.
Let's explore what they are and how to use them effectively.
What is a JWT?
A JWT (defined in RFC 7519) is a compact, URL-safe way of representing claims between parties. Think of it as a signed document that can be passed between systems. JWT recipients can always check the integrity of a JWT. (I'm focusing on signed JWTs; encrypted JWTs offer both integrity and secrecy, but are far less common in CIAM systems.)
Each signed JWT consists of three parts:
A header describing the token type and signing algorithm, as well as any other metadata
A payload containing the claims; this is a JSON object and can contain complex data structures
A signature that verifies the token's integrity
The payload is the most interesting part. It can contain both standardized claims, such as the iss
claim which represents the entity that issued the token, and the sub
claim, which represents the entity (typically the person or piece of software) which the token is about.
The signature can be generated with symmetric or asymmetric keys. Typically you'll want to use an asymmetric key, since that lets one server sign JWTs but many clients check their integrity and ingest them.
The header, payload and signature components are base64url encoded and concatenated with periods, making them safe to transmit via HTTP headers, form parameters or cookies. This means they can be easily be used over HTTP.
When JWTs Shine
JWTs are particularly valuable in distributed systems where you need to verify a token's authenticity without relying on the issuing server for every request. This is possible when the token is signed with an asymmetric key pair, allowing any system with the public key to verify the token's integrity. The public key may be pulled from the signing server periodically, or be bundled in the deployment of the service which will receive the JWT for true network isolation.
This distributed integrity verification makes JWTs excellent for:
Representing authentication events across multiple systems
Carrying authorization information in distributed architectures
Implementing stateless sessions in web applications
Your architecture and scalability requirements might allow you to use token introspection. Introspection means checking a central authority for token validity instead of using the public/private key mechanism. In this case you can use opaque tokens or JWTs. However, if you use JWTs, you can migrate away from introspection if needed.
Another benefit of JWTs is that there is a lot of documentation and processing libraries available. Because it is a widely deployed standard, you are not re-inventing the wheel when you bring them to bear where appropriate. While there are alternatives like PASETO, they are not widely supported.
Validating JWTs
Whenever you get a JWT, you should validate it carefully. It's best to rely on a library to do so because you have to do a weird back and forth dance between the header and the signature validation. You need to examine the header to determine the key that was used to sign the JWT, then use that information to find the public key that signed the content. After that signature checks you, you can trust the payload.
Did you catch that? You have to trust the header before you can validate the signature, but validating the signature is what allows you to trust the header. Use a library.
But after you have validated the signature, you still need to check claims. How you do this is business logic, but typically you'll check standard claims like the issuer, audience, and valid time window. You might also check for certain custom claims before you trust the JWT.
This claim validation is sometimes handled by common libraries, but often should be extracted to an organization or application specific library.
Common Pitfalls and Anti-patterns
While JWTs are powerful, they're not appropriate for every use case. Here are some important considerations:
First and foremost, always sign your JWTs. Unsigned JWTs (sometimes called "unsecured JWTs") provide no security guarantees and should never be used in production systems. As Brian Campbell highlighted in his comprehensive Identiverse publication on JWTs unsigned tokens are effectively just base64-encoded JSON, offering no integrity protection.
When you do use JWTs, prefer asymmetric signing algorithms like RS256 or ES256 over symmetric ones like HS256. This separation of signing and verification capabilities aligns better with most security models. (You can use HS256 if you can share a secret effectively and trust all the consumers of the JWT, but in that case why bother with JWT overhead?)
The customizability of the payload is one of the strengths of JWTs, but can balloon in size if you aren't careful. It also is not secret; don't put anything in one that should not be revealed to anyone that can read the JWT. You might want to put ids that refer to server side database rows in a JWT, rather than full details about the user.
If you are thinking about a more normal web app, rather than an API based system, using encrypted cookies may be a simpler path, as outlined here in 2017.
JWTs in CIAM
In CIAM systems, JWTs often appear in two main contexts:
ID Tokens: When using OpenID Connect, successful authentication results in an ID token, which is always a JWT. This token represents the authentication event and contains claims about the user's identity, the time of authentication, and more. Examining the token at the end of an authentication event can help servers relying on an OIDC flow make sure the user was properly authenticated.
Access Tokens: In OAuth 2.0-based systems, access tokens may be JWTs, though this isn't required by the specification. Whether to use JWTs for access tokens depends on your specific needs and willingness to accept tradeoffs:
if you need the token to carry additional data (in contrast to an API key, JWTs can carry rich payloads)
If you want to validate tokens without contacting the authorization server
If you're comfortable with the inability to immediately revoke tokens
Cheers,
Dan