feat: add RFC 8693 token exchange grant - #7759
Conversation
|
💬 Discussion in Slack: #pr-review-infisical-7759-feat-add-rfc-8693-token-exchange-grant Posted by Review Police — reviews, comments, new commits, and CI failures will stream into this channel. |
|
| GitGuardian id | GitGuardian status | Secret | Commit | Filename | |
|---|---|---|---|---|---|
| 35864000 | Triggered | Generic High Entropy Secret | 0f1f0cf | backend/e2e-test/routes/v1/oauth-token-exchange.spec.ts | View secret |
🛠 Guidelines to remediate hardcoded secrets
- Understand the implications of revoking this secret by investigating where it is used in your code.
- Replace and store your secret safely. Learn here the best practices.
- Revoke and rotate this secret.
- If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.
To avoid such incidents in the future consider
- following these best practices for managing and storing secrets including API keys and other credentials
- install secret detection on pre-commit to catch secret before it leaves your machine and ease remediation.
🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.
|
| Filename | Overview |
|---|---|
| backend/src/services/oauth-client/oauth-token-exchange-fns.ts | Implements cached, SSRF-pinned OIDC discovery/JWKS resolution and subject-token claim verification. |
| backend/src/services/oauth-client/oauth-client-service.ts | Adds token exchange, grant validation, delegated session creation, authority-race checks, and audit emission; the new audit metadata lacks labels for some identifiers. |
| backend/src/server/plugins/auth/inject-identity.ts | Recognizes delegated OAuth tokens and distinguishes scoped delegation from explicit full delegation. |
| backend/src/ee/services/permission/permission-service.ts | Intersects scoped OAuth delegation with organization and project abilities while preserving explicit full delegation. |
| backend/src/db/migrations/20260806120000_add-oauth-client-grant-types.ts | Backfills existing OAuth clients with authorization-code and refresh-token grants and adds token-exchange configuration columns. |
| backend/src/ee/services/audit-log/audit-log-types.ts | Defines the token-exchange audit event, including identifier fields that are not all paired with human-readable labels. |
| frontend/src/pages/organization/SettingsPage/components/OrgOauthClientsTab/OauthClientModal.tsx | Adds grant-flow selection and token-exchange audience/MFA configuration to the OAuth client form. |
| backend/e2e-test/routes/v1/oauth-token-exchange.spec.ts | Covers grant registration, endpoint validation, delegation markers, protected account routes, and refresh-token issuance. |
Reviews (1): Last reviewed commit: "block from deleting org" | Re-trigger Greptile
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6fdf713b4c
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
PR overviewAdds support for the RFC 8693 OAuth token exchange grant, including use of delegated tokens with dynamic-secret leasing and ACME enrollment workflows. Four security issues have been addressed, but one significant authorization-lifecycle gap remains. A holder of a full-delegation exchange token can mint infrastructure credentials or reveal ACME enrollment secrets that remain usable after the originating OAuth sessions are revoked, enabling persistent access beyond the intended revocation boundary. Open issues (1)
Fixed/addressed: 4 · PR risk: 7/10 |
| } | ||
| }, | ||
| onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), | ||
| onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN, AuthMode.OAUTH]), |
There was a problem hiding this comment.
Medium: Minted credentials outlive OAuth revocation
A client with a full-delegation exchange token can create a dynamic-secret lease—potentially returning AWS, database, or Kubernetes credentials—and continue using those credentials after its OAuth sessions are revoked. The same persistence path exists in dynamic-secret-lease-routers/kubernetes-lease-router.ts:53 and through the ACME EAB reveal routes at pki-application-enrollment-routers/acme-enrollment-router.ts:150 and certificate-profiles-router.ts:898, where the EAB secret can register an independently authenticated ACME account. Keep OAuth disabled on these issuance/bootstrap routes, or explicitly revoke the derived leases and accounts whenever the originating OAuth session or client is revoked.
Context
Middleware acting on behalf of users (MCP servers, AI agents, internal developer portals, API gateways) currently has to authenticate using a shared machine identity. This loses user attribution in the audit log and grants every user the full set of permissions assigned to that shared identity.
This change adds support for the RFC 8693 Token Exchange grant to the existing OAuth token endpoint. Trusted middleware can present a user's token issued by the organization's OIDC identity provider and receive a short-lived Infisical access token for that same user. The issued token carries the user's actual permissions and is fully attributed to them in the audit log. No refresh token is issued, and delegated tokens cannot access account self-management endpoints.
OAuth applications now explicitly declare their supported grant types. Existing applications and API clients that do not specify any grant types continue using the authorization code flow by default, so this change is fully backward compatible.
Token Exchange applications introduce one additional configuration field: the audience that the organization's identity provider issues for that middleware. This prevents tokens minted for unrelated applications from being exchanged.
The trust anchor is the organization's OIDC SSO configuration rather than per-application issuer settings. As a result, enabling Token Exchange, updating its audience, or rotating a Token Exchange application's client secret all require SSO edit permissions. Deleting a client, rotating its secret, or removing the Token Exchange grant immediately revokes any delegated tokens it has previously issued.
Screenshots
Steps to verify the change
Testing end to end locally
A complete walkthrough is available in
sso.mdunder Testing OAuth Token Exchange (RFC 8693). The abbreviated flow is:The seeded realm also includes a second client,
infisical-mcp, which represents the middleware.Sign in to http://localhost:8080/ as
admin@oidc.com, navigate to Organization Settings → OAuth Applications, create an application using the Token Exchange flow, set the audience toinfisical-mcp, and copy the generated client credentials.Then run:
Use the
id_token, not the access token. The seeded Keycloak realm does not include an audience mapper, so its access tokens do not contain anaudclaim.Finally, validate the issued token:
GET /api/v1/oauth/validatereturns200.GET /api/v1/user/me/totpreturns403, confirming delegated tokens cannot access account management endpoints.oidcorganization succeeds.sso.mdalso documents the recommended negative test cases, including cross-application replay, invalid signatures, supplying ascope, SSO disabled, MFA required, unregistered grants, and the alias requirement for users who have never signed in through SSO.Type
Checklist
type(scope): short description(scope is optional, e.g.,fix: prevent crash on syncorfix(api): handle null response).