Files
better-auth/.changeset/plugin-contribution-protocol.md
Gustavo Valverde d5e7128bf1 feat(oauth-provider): per-request token claims and contributed client-auth strategies
Two generic extension points complete the contribution surface.

A custom grant handler injects per-request claims and response fields through the
new `extra` option on the exported `createUserTokens`: `extra.accessTokenClaims`
merge into the JWT access token beneath the host-pinned claims, and
`extra.tokenResponse` into the response body beneath the standard OAuth fields.
`CreateUserTokensParams` is now exported so external grant handlers can type it.

Plugins register token-endpoint client-authentication methods through
`OAuthContributions.clientAuthStrategies`, keyed by `client_assertion_type` and
dispatched at the shared `extractClientCredentials` chokepoint (so the token,
introspection, and revocation endpoints all honor them). A method such as wallet
attestation becomes executable, not merely advertised.
2026-05-31 22:10:14 +01:00

2.3 KiB

@better-auth/core, better-auth, @better-auth/oauth-provider
@better-auth/core better-auth @better-auth/oauth-provider
minor minor minor

Add a plugin contribution protocol so plugins can extend the oauth-provider without changing better-auth. A plugin declares contributes: { "oauth-provider": { ... } } (typed via the host-augmented ContributionContracts interface) plus an optional requires list validated at startup, and the host collects them with ctx.getContributions(...) in its init.

The oauth-provider now consumes those contributions. The token endpoint dispatches plugin-registered custom grant types, the discovery documents advertise contributed grant URIs, metadata, and token-endpoint auth methods, and minted access and ID tokens include plugin-contributed claims. The grant-author helpers (createUserTokens, validateClientCredentials, basicToClientCredentials, getClient, storeToken) and the OAuthContributions contract type are now exported so grant types like CIBA, OIDC4VCI, and token exchange can ship as external packages.

A custom grant handler can inject per-request claims and response fields through the extra option on createUserTokens (its CreateUserTokensParams type is now exported): extra.accessTokenClaims merge into the JWT access token and extra.tokenResponse into the response body, both beneath the host's pinned fields. Plugins can also register token-endpoint client-authentication methods through OAuthContributions.clientAuthStrategies, keyed by client_assertion_type, so a method such as wallet attestation becomes executable rather than only advertised.

The token endpoint's grant_type parameter now accepts any registered grant URI instead of a fixed enum. An unknown grant type returns an OAuth unsupported_grant_type error response rather than a schema-validation error; valid requests for the built-in grants are unaffected.

Plugin-contributed claims can never override the host's registered or authentication-context claims; on the ID token this includes acr and auth_time. Contributed access-token claims are also surfaced when an opaque token is read through introspection, matching the JWT path. Conflicting contributions fail at startup: two plugins registering the same grant URI, a grant URI advertised without a handler (or a handler not advertised), and a grant type that is not an absolute URI all throw.