What is token?
Before introducing opaque tokens, it’s important to understand what a token is:
Tokens are used to represent and transmit secure information between parties, and they support the vast majority of authentication and authorization processes that occur on the internet behind the scenes. The two most popular types of tokens in web services are RFC 7519: JSON Web Tokens (JWT) and opaque tokens.
What is opaque token?
Opaque tokens are tokens in a proprietary format that you cannot access and typically contain some identifier to information in a server’s persistent storage.
An opaque token is one form a token can take, and access tokens and refresh tokens can exist as opaque tokens. The format of an opaque token is determined by its issuer, and it is typically a string of numbers and/or characters used to help the issuer retrieve and identify certain information in a database. Here is an example of an opaque token:
M-oxIny1RfaFbmjMX54L8Pl-KQEPeQvF6awzjWFA3iq
On the other hand, JWT is another common token format. It is a JSON string that contains all the claims and information, along with a signature from the issuer. By default, it is not encrypted, though it can be encrypted using the JSON Web Encryption (JWE) standard. Even though JWT is typically unencrypted, it does not compromise its security — the presence of the signature ensures the integrity of the token’s contents, allowing full trust in the data inside the JWT.
Unlike JWT, which contains all the information necessary to be validated directly at the protected resource, opaque tokens cannot be directly validated by the resource. Instead, they require validation by the issuer of the opaque token (usually the authorization server). This validation process is typically referred to as token introspection.
What is JWT?
In contrast to opaque tokens, a JWT is a self-contained, stateless token that carries information in a structured and readable format.
A JWT is composed of three parts: a header
, a payload
, and a signature
, each encoded in Base64URL.
Here’s an example of a JWT:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
- The
header
contains information about the type of token and the algorithm used for signing. For example,{"alg": "HS256", "typ": "JWT"}
. - The
payload
section contains claims—pieces of information about the user or the authorization—such as user ID, expiration time, and scopes. Because this data is encoded but not encrypted, anyone who has the token can decode it to see the claims, though they cannot alter it without invalidating the signature. Based on the specification and authorization server configuration, various claims can be included in the payload. This gives the token its self-contained nature. For example,{"sub": "1234567890", "name": "John Doe", "iat": 1516239022}
. - The
signature
is generated by combining the header, payload, and a secret key using the specified algorithm. This signature is used to verify the integrity of the token and ensure that it has not been tampered with.
JWTs are commonly used because they can be verified locally by the client or any service, without needing to interact with the authorization server. This makes JWTs particularly efficient for distributed systems, where multiple services might need to verify the token’s authenticity independently.
However, this convenience also comes with the responsibility of ensuring that the token’s claims are not excessively exposed, as they are visible to anyone who has access to the token. Also, JWTs are typically short lived, and the expiration time is included in the token’s claims to ensure that the token is not valid indefinitely.
Opaque access token validation
A opaque access token is validated by sending it back to the authorization server for verification. The authorization server maintains the state of issued tokens and can determine the token’s validity based on its internal storage.
- The client requests an access token from the authorization server.
- The authorization server issues an opaque token.
- The client sends the resource access request with the opaque token in the header.
- The resource provider sends a token introspection ( RFC 7662: OAuth 2.0 Token Introspection ) request to the authorization server to validate the token.
- The authorization server responds with the token information.
JWT access token validation (offline)
A JWT access token can be validated offline by the client or any service that has access to the token’s public key.
- The resource provider pre-fetches the authorization server’s public key from the OIDC discovery endpoint. The public key is used to verify the token’s signature and ensure its integrity.
- The client requests an access token from the authorization server.
- The authorization server issues a JWT token.
- The client sends the resource access request with the JWT token in the header.
- The resource provider decodes and validates the JWT token using the public key obtained from the authorization server.
- The resource provider grants access based on the token’s validity.
Use cases in OIDC
In the context of OIDC (OpenID Connect), opaque tokens and JWTs serve different purposes and are used in distinct scenarios.
Opaque tokens
- User profile retrieval:
By default, when a client requests an access token without specifying a resource and includes the openid
scope, the authorization server issues an opaque access token. This token is primarily used to retrieve user profile information from the OIDC /oidc/userinfo
endpoint. Upon receiving a request with the opaque access token, the authorization server checks its internal storage to retrieve the associated authorization information and verifies the token’s validity before responding with the user profile details.
- Refresh token exchange:
Refresh tokens are designed to be exchanged only between the client and the authorization server, without needing to be shared with resource providers. As such, refresh tokens are typically issued as opaque tokens. When the current access token expires, the client can use the opaque refresh token to obtain a new access token, ensuring continuous access without re-authenticating the user.
JWTs
- ID token:
In OIDC, the ID token is a JWT that contains user information and is used to authenticate the user. Typically issued alongside the access token, the ID token allows the client to verify the user’s identity. For example:
// Decoded payload of an ID token
{
"iss": "<https://logto.io>",
"sub": "1234567890",
"aud": "client_id",
"exp": 1630368000,
"name": "John Doe",
"email": "[email protected]",
"picture": "<https://example.com/johndoe.jpg>"
}
The client can validate the ID token to ensure the user’s identity and extract user information for personalization or authorization purposes. ID token is for one-time use only and should not be used for API resource authorization.
- API resource access (using access token):
When a client requests an access token with a specific resource indicator, the authorization server issues a JWT access token intended for accessing that resource. The JWT contains claims that the resource provider can use to authorize the client’s access. For example:
// Decoded payload of a JWT access token
{
"iss": "<https://dev.logto.app>",
"sub": "1234567890",
"aud": "<https://api.example.com>",
"scope": "read write",
"exp": 1630368000
}
The resource provider can validate the request by checking the claims:
iss
: Confirms the token was issued by a trusted authorization server.sub
: Identifies the user associated with the token.aud
: Ensures the token is intended for the specific resource.scope
: Verifies the permissions granted to the user.