Tokens are used to represent and transmit security information between parties, and they silently power a large part of the authentication and authorization that happens on the internet. In web services, the two most popular kinds of tokens are JSON Web Tokens (JWTs) and opaque tokens.
A JWT is a JSON string that contains all the claims and information it represents and is certified by a signature from the issuer. By default, it’s unencrypted, but it can be encrypted via the JSON Web Encryption (JWE) standard.
On the other hand, an opaque token's format is chosen by the issuer of the token. Usually, it's a string of numbers and/or characters that identifies some information in the database of the issuer. This is in contrast to JWTs where the holder of the token can't inspect it without contacting the issuer (ie the contents are opaque).
In this article, you'll learn why you need JWT and opaque tokens, what the differences are between the two, and in which case you should select one or the other.
Why You Need JWTs and Opaque Tokens
In contrast to simpler methods for managing identification and access, JWTs and opaque tokens offer a few advantages, including the ability to share your identity or authorization to a third party. These tokens can be used to enable you to log in with your Google account to third-party websites and enable third parties to access private information, like your Gmail contacts.
They also offer you fine-grained access control. Providing a username and password is an all-or-nothing proposal, so you probably don't want to share that information with a third party. In the OAuth 2.0 protocol, tokens enable delegating a certain scope of actions to a third party, which means that they will only be able to do things that you've explicitly consented to.
While JWTs and opaque tokens have a lot in common, there are some notable differences that should be considered.
Differences between JWTs and Opaque Tokens
The main difference between JWTs and opaque tokens is that an unencrypted JWT can be interpreted by anybody that holds the token, whereas opaque tokens cannot.
An unencrypted JWT consists of three parts: a header, a payload, and a signature. The header contains the name of the token type and the signing algorithm used for the signature. The payload, which is the contents of the token, is encoded but not encrypted, so anybody can read it. The signature makes sure that the payload is not tampered with. There are [examples of encoded and decoded JWTs] available that you can experiment with to learn more.
A JWT that's encrypted adds a few more layers that deal with the encryption information like the key used. You can find more information about the JSON Web Encryption (JWE) standard here.
In addition, a JWT is meant to be stateless and self-contained—it has all the information the server needs except the signing keys, so the server doesn't need to store this information server-side. This means that users can get a token from your authorization server and use it in another without those servers needing to consult a central service.
However, this doesn't always play out perfectly. For example, a self-contained token that is issued is not easy to revoke, but there are a few ways to work around this. For example, you can add an
exp claim which signifies an expiration date for the token. Or you can use the
jti claim to assign a valid identifier. Using the identifiers, you can create blacklists to block certain token identifiers.
Opaque tokens cannot be read by people that hold them since they are undecodable strings. A client cannot read the contents of the token without interacting with the authorization server by querying an introspection endpoint or checking the claims of the token with the userinfo endpoint.
When to Use Opaque Tokens Instead of JWTs
If you classify tokens by their purpose (and not format), you end up with two main types of security tokens: ID tokens, which are introduced by OpenID Connect, and access tokens, which are introduced by OAuth 2.0.
ID tokens are tokens that a server issues to prove that the user is authenticated. You can use them to log into third-party services with another service that acts as an identity provider, like Google. The service will issue you an ID token (ie a token confirming your identity) that you can use with a third-party service. The OpenID Connect protocol requires you to use JWTs for ID tokens.
Access tokens can grant permission for a third party to act on your behalf in some kind of service. In this case, the service will issue the third party an access token (ie a token that enables it to take certain actions).
OAuth 2.0 doesn’t prescribe a specific format for access tokens, so you can use opaque tokens, JWT, or any other format that satisfies the necessary properties. This means that, technically, you can use JWTs for providing access tokens; however, JWTs have certain downsides that become much more prominent when working with access tokens.
Following are three situations when you would want to use opaque tokens instead of JWTs:
When You're Transmitting Sensitive Information
By default, JWT is encoded but not encrypted. This means that anyone that gets ahold of a token can read the contents of that token. This can be harmful when the attacker uses the contents of the token to gain information such as the user's role or even personally identifiable information.
You can encrypt the token using the JSON Web Encryption (JWE) standard so that it can only be read by the intended recipient. But this comes with its own challenges in cryptographic key distribution and management.
All in all, securing JWTs is somewhat complicated, so using them for sensitive data adds unnecessary complexity and risk. Opaque tokens are not readable by default, so if you're transmitting sensitive information, they're usually the better option.
When You Want to Revoke Tokens
JWTs are supposed to be self-contained. Once you issue one, you have no possibility to edit the contents of the token since it rests with the client. This means that every token that you issue is prone to become outdated. For this reason, these tokens are usually created with an expiration time of a few minutes.
In contrast, opaque tokens are stored on the server. So you can change their contents at will. If a user is banned or deleted, or if any other action is taken that would invalidate their token, you can instantly revoke the token that is residing in your storage. There is no window to use an invalid token.
For this reason, JWT tokens are a bad choice for storing long-lasting authorization and session data. Because of the necessity to include an expiration date with your tokens, you can't really issue them for too long. And if you want to end a session, you can't really make the token invalid.
It's possible to issue unique identifiers to tokens and use allowlists, denylists, or centralized database tables to manage the access that issued JWT tokens have, but this defeats the purpose of having a stateless, self-contained token to some degree.
When You Care about Payload Size
A token needs to be attached to every request that the client makes to the server. If the payload size is small, this is no issue. But a larger token can gobble up more than its fair share of bandwidth.
In contrast, an opaque token can store much more information since the data resides in a server . The client only needs to send the string that you have issued over the wire. This string, in turn, enables your server to look up the token in its database or authorization service.
Can Using JWTs be Advantageous?
Although the format of JWTs have quite a few downsides, there are some situations where the self-sufficient nature of JWTs shine.
For example, if your system is highly distributed, querying the authorization server for the token details of opaque tokens may create additional internal traffic to the server, increase overall latency, and create a bottleneck for the system.
If your use case is simple, you’re not transmitting sensitive information, and you're not concerned about revoking tokens, JWTs are the superior choice.
JWTs are stateless, self-contained tokens that are encoded but not encrypted. For this reason, JWTs should be used to create small tokens that don't contain sensitive information and don't need to be revoked.
In contrast, opaque tokens are strings that point to data on the server. By design, they cannot be read by their holders. Therefore, this method should be used to create tokens that contain sensitive information. In addition, since the tokens are stored on the server, they can carry more data than JWTs, and you can easily revoke them if necessary.
By now, you should have a better understanding of when and how to use JWTs and opaque tokens. If you want more information about authentication and authorization, OAuth 2.0 has an official page with the industry standard authorization protocol as well as links to more resources on this topic.
ZITADEL is an open source identity management platform that provides you with a wide range of features like OpenID Connect, SAML 2.0, OAuth 2, FIDO2, OTP, and an unlimited audit trail. With ZITADEL, you can solve all your authentication and authorization needs. Check out our repo and give us a GitHub star. We appreciate the feedback.
This article was contributed by Gints Dreimanis.