You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Native encrypted access tokens with single and multi-recipient JWE
#51721
We are interested in contributing an implementation and have been reviewing the current Keycloak token/JOSE infrastructure, previous community attempts, and the relevant OAuth, OpenID Connect, and JOSE specifications.
The main goal is to provide confidentiality for Access Token claims while preserving the existing signed JWT behavior by default.
Conceptually:
Access Token Claims
|
v
JWS
|
v
Signed JWT
|
v
JWE
|
v
Encrypted Access Token
The proposal is fully opt-in. Existing clients without Access Token encryption configuration should continue receiving Access Tokens exactly as they do today.
A more detailed design proposal is available here:
Single-recipient encrypted Access Tokens using JWE Compact Serialization;
Signed-then-encrypted Access Tokens using nested JOSE;
Configurable key-management and content-encryption algorithms;
Resource-server-specific encryption keys;
Keycloak as an optional decryption recipient;
Multi-recipient encryption using General JWE JSON Serialization;
Public SPA clients that can transport an encrypted Access Token without decrypting it;
Confidential clients and BFF architectures;
Gateways and APIs performing local JWE decryption;
End-to-end user-token propagation;
Token Exchange and resource-specific delegated tokens;
Client Credentials / M2M scenarios;
Compatibility with UserInfo, Introspection, Revocation, Token Exchange, UMA, DPoP, mTLS, Admin APIs, and other Access Token consumers;
Admin Console configuration;
Backwards compatibility with existing clients.
Single-recipient JWE
The least controversial initial implementation appears to be JWE Compact Serialization.
For example:
Keycloak
|
| JWE Compact Access Token
v
SPA / OAuth Client
|
| opaque token
v
Resource Server
|
| recipient private key
v
Decrypt JWE
|
v
Verify nested JWS
The requesting OAuth client does not necessarily need to be the cryptographic recipient.
For example, a public SPA could receive and propagate an encrypted Access Token intended for an API without having access to the API's private encryption key.
Resource Server vs requesting client
One important design point is that Access Token encryption has different recipient semantics from ID Token encryption.
For an ID Token, the recipient is naturally the OIDC client.
For an Access Token, the cryptographic recipient is normally the Resource Server or an enforcement gateway.
RFC 8707 Resource Indicators looks particularly relevant here because the Authorization Server may need to know the target Resource Server in order to encrypt the Access Token using that resource's public key.
Multi-recipient use case
There are scenarios where both the Resource Server and Keycloak itself may need to decrypt the same Access Token.
Examples include tokens later presented to:
UserInfo;
Introspection;
Token Exchange;
Revocation;
UMA / Authorization Services;
Admin or Account APIs.
Sharing a Resource Server private key with Keycloak would be undesirable.
RFC 7516 General JWE JSON Serialization provides another model:
CEK
|
+-----------+-----------+
| |
v v
Keycloak Public Key API Public Key
| |
v v
Encrypted CEK #1 Encrypted CEK #2
The ciphertext is generated once, while the CEK is independently protected for each recipient.
Each recipient keeps an independent private key.
JWE JSON transport
This introduces an interoperability question.
JWE General JSON Serialisation supports multiple recipients but cannot be used directly in an RFC 6750 Bearer credential as raw JSON.
One possible transport profile would be:
BASE64URL(
UTF8(
JWE General JSON Serialization
)
)
However, this outer Base64URL representation would be a Keycloak-defined transport profile, not an RFC 7516 serialization.
This is one of the main areas where we would like maintainer/community feedback before defining a public API.
A versioned representation such as:
kc-jwe-json-v1.<base64url-payload>
Could also make server-side format detection deterministic, but would introduce an additional Keycloak-specific convention.
Browser clients / keycloak-js
A public SPA should not need to possess a static JWE private key simply to use an encrypted Access Token.
Instead:
ID Token / UserInfo
→ client identity and UI claims
Access Token
→ opaque credential for Resource Server
The SPA could still use ID Token or UserInfo claims for UI decisions such as navigation, user display information, or feature visibility, while actual authorization remains enforced by the Resource Server.
This may require keycloak-js to stop assuming that every Access Token is locally parseable.
For example, token lifetime management could rely on OAuth token response metadata such as expires_in instead of requiring the Access Token exp claim.
ID Token and UserInfo
Access Token, ID Token, and UserInfo encryption should remain independent.
Their intended recipients differ:
ID Token → OIDC client
UserInfo → OIDC client
Access Token → Resource Server / gateway
A typical SPA could therefore use:
ID Token:
signed, readable by SPA
UserInfo:
JSON or signed
Access Token:
encrypted, opaque to SPA
While a confidential BFF may choose encrypted ID Token and UserInfo responses as well.
Reference scenarios
The design currently considers reference implementations for:
SPA → API
Browser → BFF → API
SPA → API-A → API-B → API-C
same end-user token
SPA → API-A
|
| Token Exchange
v
API-B
Service-A
|
| Client Credentials
v
Service-B
We would also like to eventually add corresponding examples to keycloak-quickstarts.
Relevant specifications
The main specifications considered so far are:
RFC 6749 - OAuth 2.0
RFC 6750 - Bearer Token Usage
RFC 7515 - JWS
RFC 7516 - JWE
RFC 7517 - JWK
RFC 7518 - JWA
RFC 7519 - JWT
RFC 7591 - Dynamic Client Registration
RFC 8414 - Authorization Server Metadata
RFC 8693 - Token Exchange
RFC 8705 - Mutual TLS
RFC 8707 - Resource Indicators
RFC 8725 - JWT Best Current Practices
RFC 9068 - JWT Profile for OAuth Access Tokens
RFC 9449 - DPoP
RFC 9728 - Protected Resource Metadata
OpenID Connect Core 1.0
Questions for maintainers/community
Before starting implementation, we would especially appreciate feedback on these points:
Should the initial implementation focus on JWE Compact / single-recipient encryption and add multi-recipient support incrementally?
Does supporting General JWE JSON Serialization for Access Tokens make sense for Keycloak?
If General JWE JSON is supported, would BASE64URL(JWE General JSON) be an acceptable Bearer transport profile, or should another approach be considered?
If a Keycloak-specific transport profile is necessary, should it have explicit identification/versioning?
Should Access Token encryption policy primarily belong to the requesting client, the target Resource Server, the realm, or a combination with defined precedence?
Should RFC 8707 resource be a primary input for selecting the encryption recipient?
Could RFC 9728 Protected Resource Metadata / jwks_uri be used as a standards-based mechanism for discovering Resource Server encryption public keys?
Should Keycloak optionally be included as an independent JWE recipient to support server-side token consumers without sharing Resource Server private keys?
How should multiple audiences/resources interact with recipient resolution?
Should keycloak-js explicitly support encrypted/opaque Access Tokens without requiring local token parsing?
Should Refresh Token encryption be treated as separate follow-up work after Access Token encryption?
Should multi-recipient support initially be considered experimental until the Bearer transport representation is agreed upon?
The intent is to agree on the architecture and public protocol/configuration surface before starting the implementation.
Feedback on scope, standards alignment, and how this should be broken into incremental contributions would be very welcome.
Hi @mposolda, I’ve been working on a design proposal for native encrypted Access Tokens in Keycloak, based on #19464 and previous JWE-related work such as #7341.
I opened this discussion and a Draft design proposal to get feedback before starting any implementation. Since this touches OAuth/OIDC token issuance, JOSE, token consumption, and potentially resource-aware encryption, I’d really appreciate your thoughts on the proposed direction and initial scope when you have some time.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Motivation
There is an existing feature request, [#19464 - Encrypt Access and Refresh Tokens](#19464), requesting native support for encrypted access tokens.
We are interested in contributing an implementation and have been reviewing the current Keycloak token/JOSE infrastructure, previous community attempts, and the relevant OAuth, OpenID Connect, and JOSE specifications.
The main goal is to provide confidentiality for Access Token claims while preserving the existing signed JWT behavior by default.
Conceptually:
The proposal is fully opt-in. Existing clients without Access Token encryption configuration should continue receiving Access Tokens exactly as they do today.
A more detailed design proposal is available here:
https://github.com/csfreitas/keycloak-community/blob/design/encrypted-access-tokens/design/encrypted-access-tokens.md
Proposed capabilities
The design considers the following capabilities:
Single-recipient JWE
The least controversial initial implementation appears to be JWE Compact Serialization.
For example:
The requesting OAuth client does not necessarily need to be the cryptographic recipient.
For example, a public SPA could receive and propagate an encrypted Access Token intended for an API without having access to the API's private encryption key.
Resource Server vs requesting client
One important design point is that Access Token encryption has different recipient semantics from ID Token encryption.
For an ID Token, the recipient is naturally the OIDC client.
For an Access Token, the cryptographic recipient is normally the Resource Server or an enforcement gateway.
For example:
RFC 8707 Resource Indicators looks particularly relevant here because the Authorization Server may need to know the target Resource Server in order to encrypt the Access Token using that resource's public key.
Multi-recipient use case
There are scenarios where both the Resource Server and Keycloak itself may need to decrypt the same Access Token.
Examples include tokens later presented to:
Sharing a Resource Server private key with Keycloak would be undesirable.
RFC 7516 General JWE JSON Serialization provides another model:
The ciphertext is generated once, while the CEK is independently protected for each recipient.
Each recipient keeps an independent private key.
JWE JSON transport
This introduces an interoperability question.
JWE General JSON Serialisation supports multiple recipients but cannot be used directly in an RFC 6750 Bearer credential as raw JSON.
One possible transport profile would be:
The OAuth response would still contain a string:
{ "access_token": "eyJwcm90ZWN0ZWQiOi...", "token_type": "Bearer", "expires_in": 300 }And the value could still be propagated as:
Authorization: Bearer eyJwcm90ZWN0ZWQiOi...However, this outer Base64URL representation would be a Keycloak-defined transport profile, not an RFC 7516 serialization.
This is one of the main areas where we would like maintainer/community feedback before defining a public API.
A versioned representation such as:
Could also make server-side format detection deterministic, but would introduce an additional Keycloak-specific convention.
Browser clients / keycloak-js
A public SPA should not need to possess a static JWE private key simply to use an encrypted Access Token.
Instead:
The SPA could still use ID Token or UserInfo claims for UI decisions such as navigation, user display information, or feature visibility, while actual authorization remains enforced by the Resource Server.
This may require
keycloak-jsto stop assuming that every Access Token is locally parseable.For example, token lifetime management could rely on OAuth token response metadata such as
expires_ininstead of requiring the Access Tokenexpclaim.ID Token and UserInfo
Access Token, ID Token, and UserInfo encryption should remain independent.
Their intended recipients differ:
A typical SPA could therefore use:
While a confidential BFF may choose encrypted ID Token and UserInfo responses as well.
Reference scenarios
The design currently considers reference implementations for:
We would also like to eventually add corresponding examples to
keycloak-quickstarts.Relevant specifications
The main specifications considered so far are:
Questions for maintainers/community
Before starting implementation, we would especially appreciate feedback on these points:
Should the initial implementation focus on JWE Compact / single-recipient encryption and add multi-recipient support incrementally?
Does supporting General JWE JSON Serialization for Access Tokens make sense for Keycloak?
If General JWE JSON is supported, would
BASE64URL(JWE General JSON)be an acceptable Bearer transport profile, or should another approach be considered?If a Keycloak-specific transport profile is necessary, should it have explicit identification/versioning?
Should Access Token encryption policy primarily belong to the requesting client, the target Resource Server, the realm, or a combination with defined precedence?
Should RFC 8707
resourcebe a primary input for selecting the encryption recipient?Could RFC 9728 Protected Resource Metadata /
jwks_uribe used as a standards-based mechanism for discovering Resource Server encryption public keys?Should Keycloak optionally be included as an independent JWE recipient to support server-side token consumers without sharing Resource Server private keys?
How should multiple audiences/resources interact with recipient resolution?
Should
keycloak-jsexplicitly support encrypted/opaque Access Tokens without requiring local token parsing?Should Refresh Token encryption be treated as separate follow-up work after Access Token encryption?
Should multi-recipient support initially be considered experimental until the Bearer transport representation is agreed upon?
The intent is to agree on the architecture and public protocol/configuration surface before starting the implementation.
Feedback on scope, standards alignment, and how this should be broken into incremental contributions would be very welcome.
All reactions
Replies: 1 comment
Uh oh!
There was an error while loading. Please reload this page.
Hi @mposolda, I’ve been working on a design proposal for native encrypted Access Tokens in Keycloak, based on #19464 and previous JWE-related work such as #7341.
I opened this discussion and a Draft design proposal to get feedback before starting any implementation. Since this touches OAuth/OIDC token issuance, JOSE, token consumption, and potentially resource-aware encryption, I’d really appreciate your thoughts on the proposed direction and initial scope when you have some time.
The Draft proposal is here: keycloak/keycloak-community#358.
In particular, I’m considering starting with JWE Compact / single-recipient support and treating multi-recipient JWE as follow-up work.
All reactions