|
|
|
|
@ -123,8 +123,10 @@ sequenceDiagram
|
|
|
|
|
|
|
|
|
|
Clients can request ID-JAG tokens from Dex's `/token` endpoint by specifying |
|
|
|
|
`requested_token_type=urn:ietf:params:oauth:token-type:id-jag` in a |
|
|
|
|
Token Exchange request. ID-JAG support is gated behind a feature flag |
|
|
|
|
(`enableIDJAG`) and disabled by default. |
|
|
|
|
Token Exchange request. ID-JAG support is enabled by adding |
|
|
|
|
`urn:ietf:params:oauth:token-type:id-jag` to `oauth2.tokenExchange.tokenTypes`. |
|
|
|
|
When not listed, requests with this `requested_token_type` are rejected, |
|
|
|
|
ensuring no change in behavior for existing deployments. |
|
|
|
|
|
|
|
|
|
The request parameters (extending existing Token Exchange): |
|
|
|
|
|
|
|
|
|
@ -152,25 +154,58 @@ The response:
|
|
|
|
|
- `issued_token_type`: `urn:ietf:params:oauth:token-type:id-jag` |
|
|
|
|
- `token_type`: `N_A` (this is not an OAuth access token) |
|
|
|
|
- `expires_in`: lifetime in seconds (default: 300, configurable independently of ID token |
|
|
|
|
lifetime via `idJAGTokensValidFor`) |
|
|
|
|
lifetime via `expiry.idJAGTokens`) |
|
|
|
|
- `scope`: OPTIONAL if the issued scope is identical to the requested scope; REQUIRED |
|
|
|
|
otherwise. Per Section 4.3.2 of the specification, policy evaluation at the IdP may |
|
|
|
|
result in different scopes being issued than were requested. |
|
|
|
|
|
|
|
|
|
ID-JAG policy configuration: |
|
|
|
|
Complete configuration example: |
|
|
|
|
|
|
|
|
|
```yaml |
|
|
|
|
tokenExchange: |
|
|
|
|
enableIDJAG: true # default: false; feature flag for ID-JAG support |
|
|
|
|
idJAGTokensValidFor: "5m" # default: 5m; independent of idTokensValidFor |
|
|
|
|
idJAGPolicies: |
|
|
|
|
- clientID: "wiki-app" |
|
|
|
|
oauth2: |
|
|
|
|
grantTypes: |
|
|
|
|
- authorization_code |
|
|
|
|
- urn:ietf:params:oauth:grant-type:token-exchange |
|
|
|
|
tokenExchange: |
|
|
|
|
# List of token types enabled for exchange. Adding id-jag enables ID-JAG support. |
|
|
|
|
# Omitting it (default) disables ID-JAG without affecting other token exchange flows. |
|
|
|
|
# SAML2 (urn:ietf:params:oauth:token-type:saml2) may be added in a future release. |
|
|
|
|
tokenTypes: |
|
|
|
|
- urn:ietf:params:oauth:token-type:id_token |
|
|
|
|
- urn:ietf:params:oauth:token-type:id-jag |
|
|
|
|
|
|
|
|
|
expiry: |
|
|
|
|
idTokens: "24h" |
|
|
|
|
idJAGTokens: "5m" # default: 5m; independent of idTokens |
|
|
|
|
|
|
|
|
|
staticClients: |
|
|
|
|
- id: wiki-app |
|
|
|
|
name: "Wiki Application" |
|
|
|
|
secret: "wiki-secret" |
|
|
|
|
redirectURIs: |
|
|
|
|
- "https://wiki.example/callback" |
|
|
|
|
# Per-client ID-JAG policy. Clients without this section cannot obtain ID-JAG tokens |
|
|
|
|
# (default-deny). Only audiences and scopes listed here may be requested. |
|
|
|
|
idJAGPolicies: |
|
|
|
|
allowedAudiences: |
|
|
|
|
- "https://chat.example/" |
|
|
|
|
- "https://calendar.example/" |
|
|
|
|
allowedScopes: |
|
|
|
|
- "chat.read" |
|
|
|
|
- "calendar.read" |
|
|
|
|
|
|
|
|
|
- id: supermarket-app |
|
|
|
|
name: "Supermarket Application" |
|
|
|
|
secret: "supermarket-secret" |
|
|
|
|
redirectURIs: |
|
|
|
|
- "https://supermarket.example/callback" |
|
|
|
|
idJAGPolicies: |
|
|
|
|
allowedAudiences: |
|
|
|
|
- "https://grocery.store.1/" |
|
|
|
|
- "https://grocery.store.2/" |
|
|
|
|
allowedScopes: |
|
|
|
|
- "eat.bananas" |
|
|
|
|
- "eat.apples" |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
### Implementation Details/Notes/Constraints |
|
|
|
|
@ -179,14 +214,18 @@ tokenExchange:
|
|
|
|
|
per Section 3 of the specification (header `typ: "oauth-id-jag+jwt"`, claims including |
|
|
|
|
`iss`, `sub`, `aud`, `client_id`, `jti`, `exp`, `iat`). |
|
|
|
|
|
|
|
|
|
- A new config-based policy evaluator controls which clients can request ID-JAGs for which |
|
|
|
|
audiences, with a default-deny posture when policies are configured. |
|
|
|
|
- Per-client `idJAGPolicies` in `staticClients` control which audiences and scopes a |
|
|
|
|
given client may request in an ID-JAG. Clients without `idJAGPolicies` are denied |
|
|
|
|
by default. Dynamically registered clients are currently unsupported for ID-JAG policies; |
|
|
|
|
support via DB-stored policies or CEL expressions (#4601) is deferred to a future release. |
|
|
|
|
|
|
|
|
|
- OIDC discovery is extended with `id_jag_signing_alg_values_supported` per Section 6. |
|
|
|
|
- OIDC discovery is extended with `identity_chaining_requested_token_types_supported` per |
|
|
|
|
Section 6 of the specification. When ID-JAG is enabled, Dex includes |
|
|
|
|
`urn:ietf:params:oauth:token-type:id-jag` in this metadata property. |
|
|
|
|
|
|
|
|
|
- ID-JAG support is gated behind the `enableIDJAG` feature flag. When disabled (default), |
|
|
|
|
requests with `requested_token_type=urn:ietf:params:oauth:token-type:id-jag` are |
|
|
|
|
rejected, ensuring no change in behavior for existing deployments. |
|
|
|
|
- ID-JAG support is enabled by listing `urn:ietf:params:oauth:token-type:id-jag` in |
|
|
|
|
`oauth2.tokenExchange.tokenTypes`. When not listed (default), requests are rejected, |
|
|
|
|
ensuring no change in behavior for existing deployments. |
|
|
|
|
|
|
|
|
|
### Risks and Mitigations |
|
|
|
|
|
|
|
|
|
@ -198,11 +237,14 @@ tokenExchange:
|
|
|
|
|
- **Replay attack risk**: Server-side `jti` tracking is deferred, so a stolen ID-JAG |
|
|
|
|
can be replayed within its 5-minute lifetime. Short `expires_in` is the only Dex-side |
|
|
|
|
mitigation; Resource Authorization Servers should implement `jti` caching independently. |
|
|
|
|
- **Public client misuse**: Per Section 7.1 of the specification, ID-JAG SHOULD only be |
|
|
|
|
used by confidential clients. Public clients should use the standard authorization code |
|
|
|
|
flow with interactive user consent at the Resource Authorization Server. Dex will enforce |
|
|
|
|
this by rejecting ID-JAG requests from public clients (clients without a secret). |
|
|
|
|
- **Breaking changes**: None. This is purely additive to the existing |
|
|
|
|
Token Exchange implementation. The `audience` parameter is newly introduced |
|
|
|
|
(not previously used in the implementation despite DEP #2812's original proposal), |
|
|
|
|
and `connector_id` already exists. The feature flag ensures existing deployments |
|
|
|
|
are unaffected. |
|
|
|
|
and `connector_id` already exists. |
|
|
|
|
|
|
|
|
|
### Alternatives |
|
|
|
|
|
|
|
|
|
|