OAuth 2.0 has become the standard authorization framework for securing APIs. At the heart of OAuth 2.0 are access tokens, credentials that allow an application to access protected resources on behalf of a user or itself.
Typically, access tokens indicate that the client app has been granted permissions to access specific resources, such as user data.
OAuth 2.0 itself doesn't specify a format for access tokens, leading many implementations to adopt proprietary token formats. RFC 9068 addresses this by defining a standardized JSON Web Token (JWT) profile for OAuth 2.0 access tokens, enabling better interoperability and security.
Why JWT access tokens?
Originally, OAuth 2.0 tokens were opaque strings requiring additional calls to authorization servers for validation (token introspection). JWT access tokens eliminate this overhead by embedding structured token information directly into a cryptographically signed JWT, allowing resource servers to independently validate tokens.
For developers, RFC 9068 simplifies token validation by eliminating additional round trips to authorization servers for token introspection.
Practical example: E-commerce API
Consider an e-commerce mobile app that allows customers to view their profile information, manage orders, and check their purchase history. To access these protected resources, the app needs an access token issued by an authorization server after successful user authentication. This access token authorizes the app to interact securely with the e-commerce resource server at `https://api.ecommerce.com`.
Structure of a JWT access token
JWT access tokens contain standardized claims within their payload. RFC 9068 specifies the following required claims:
iss (Issuer): URL identifying the authorization server.
sub (Subject): Identifier for the customer or client application.
aud (Audience): Identifies the intended resource server.
exp (Expiration): Indicates when the token becomes invalid.
iat (Issued At): Timestamp of token issuance.
jti (JWT ID): Unique identifier to prevent replay attacks.
client_id: Identifier of the OAuth client application.
Here's a sample JWT access token for our e-commerce app:
Requesting a JWT access token
The mobile app explicitly requests JWT access tokens by including a resource
parameter and scopes within the authorization request. Here’s an example request:
The resulting JWT token issued upon successful authorization looks like this:
Header:
- kid (Key ID): Identifies the specific key used by the authorization server to sign the token.
Validating JWT access tokens
The e-commerce resource server validates JWT access tokens independently by:
- Verifying the token's signature using public keys advertised by the authorization server.
- Ensuring token claims (
iss
,aud
,exp
) match expected values. - Checking that the token type (
typ
) header explicitly statesat+jwt
.
Here's a simplified Node.js validation logic example for our e-commerce API:
Security considerations
RFC 9068 mandates specific practices to ensure security:
- JWT access tokens MUST NOT use the
none
algorithm. - Tokens should clearly distinguish themselves from OpenID Connect ID tokens (typ header set to at+jwt).
- Authorization servers should use distinct identifiers (
aud
) for different resources to avoid cross-JWT confusion.
Privacy considerations
As JWT tokens carry user information, the e-commerce authorization server must consider privacy implications:
- Avoid including unnecessary sensitive information.
- Encrypt tokens or sensitive claims when necessary.
- Use unique subject (
sub
) identifiers per resource to prevent tracking across resource servers.
Developer best practices
- Regularly rotate signing keys and publish them via JWKS endpoint.
- Ensure clock synchronization (for claim validation like exp and iat).
- Clearly document the claims used within your JWT tokens for consumer APIs.
Edge cases to watch out for
- Token reuse across multiple resources causing JWT confusion.
- Handling token expiration gracefully on resource servers.
- Ensuring public key availability for JWT signature validation.
When NOT to use this RFC
This RFC can be avoided in highly sensitive environments requiring opaque tokens and frequent token introspection. It’s also best avoided if there is limited support for cryptographic operations.
Conclusion
RFC 9068 brings standardization to JWT access tokens, facilitating secure, efficient, and interoperable OAuth 2.0 implementations. This standardized profile reduces complexity and enhances security by clearly defining token structure, issuance, and validation processes.
By adopting RFC 9068, developers and organizations can ensure their OAuth 2.0 implementations are more secure.