[PR #4163] [MERGED] feat(oauth-provider): an oauth 2.1 compliant plugin #13477

Closed
opened 2026-04-13 08:57:50 -05:00 by GiteaMirror · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/better-auth/better-auth/pull/4163
Author: @dvanmali
Created: 8/22/2025
Status: Merged
Merged: 12/22/2025
Merged by: @dvanmali

Base: canaryHead: oauth2.1


📝 Commits (7)

  • 7eb90a9 feat: oauth 2.1 provider plugin
  • 3eade9c feat: OIDC prompt='create' and account registration callbacks
  • ed3b692 chore: restore versioning
  • 8d42a06 docs: suggestions and update schema
  • 5b522ff chore: pnpm-lock.yaml only
  • d2499da chore: oauth consent demo move
  • 1defa68 chore: bump version

📊 Changes

70 files changed (+18739 additions, -62 deletions)

View changed files

demo/nextjs/app/(auth)/oauth/consent/consent-buttons.tsx (+47 -0)
demo/nextjs/app/(auth)/oauth/consent/page.tsx (+140 -0)
demo/nextjs/app/(auth)/oauth/select-account/account-button.tsx (+69 -0)
demo/nextjs/app/(auth)/oauth/select-account/page.tsx (+37 -0)
demo/nextjs/app/(auth)/oauth/select-organization/org-buttons.tsx (+75 -0)
demo/nextjs/app/(auth)/oauth/select-organization/page.tsx (+54 -0)
demo/nextjs/app/.well-known/oauth-authorization-server/route.ts (+18 -0)
demo/nextjs/app/.well-known/oauth-protected-resource/api/mcp/route.ts (+22 -0)
demo/nextjs/app/.well-known/oauth-protected-resource/route.ts (+20 -0)
demo/nextjs/app/.well-known/openid-configuration/route.ts (+18 -0)
📝 demo/nextjs/app/api/auth/[...all]/route.ts (+42 -1)
demo/nextjs/app/api/mcp/route.ts (+90 -0)
📝 demo/nextjs/app/page.tsx (+4 -0)
📝 demo/nextjs/lib/auth-client.ts (+2 -0)
📝 demo/nextjs/lib/auth.ts (+104 -1)
demo/nextjs/lib/server-client.ts (+7 -0)
📝 demo/nextjs/package.json (+3 -0)
📝 docs/components/sidebar-content.tsx (+23 -0)
📝 docs/content/docs/plugins/mcp.mdx (+4 -0)
docs/content/docs/plugins/oauth-provider.mdx (+1830 -0)

...and 50 more files

📄 Description

oAuth 2.1 Provider

An upgrade to oidc-provider plugin that makes it oauth2.1 compliant and has a configuration that is secure by default.

Plans for the deprecation of oidc-provider plugin due to many inherent flaws in its design. Internally, plugin functions now share logic, providing for better future extensibility if new code_grants need to be written or user/client jwt or opaque tokens need to be written. Furthermore, as an oAuth 2.1 provider, it provides logic valid for an MCP server. When using the scope "openid" (optional, enabled by default), the server acts like an OpenId server able to issue id tokens and provides a /userinfo endpoint.

Features

  • OAuth 2.1 by default
    • Properly supports authorization_code, refresh_token, and client_credentials grants
    • PKCE by default (removes plain completely)
  • Public and confidential client registration
  • JWT plugin is required by default, but can be disabled using disableJWTPlugin flag
  • Access tokens can now be received in JWT verifiable format using the resource parameter (ie JWT aud field)
  • Id tokens are still verifiable by JWKS when using JWT Plugin, or clientSecret if disabled. Fixes issue to prevent public clients when disableJWTPlugin: true from obtaining id tokens directly even when they shouldn't be allowed an id token and should use /userinfo instead.
  • Protects /userinfo with scope check
  • Separates Refresh Token and Access token on database schema to allow multiple access tokens per refresh and multiple refresh tokens per login session.
  • oauthAccessToken strictly deals with opaque tokens
    • Opaque tokens are given only when resource parameter (aka audience) is not provided
  • Option to Encode and Decode refresh tokens
  • allowDynamicClientRegistration with allowUnauthenticatedClientRegistration flags
  • Separation of default expiration times
  • Proper creation of public and confidential clients
  • Prevents misconfiguration between .well-known/openid-configuration endpoint and plugin settings
  • scopeExpirations to assign scopes specific expiration
  • Custom claims through separated functions: customAccessTokenClaims, customIdTokenClaims, and customUserInfoClaims
  • Organizational support through activeOrganizationalId on a session such as through the organizational plugin. Attaches to oAuthClient via reference_id.
  • Rp-initiated logout
  • Account Selection via prompt=select_account.
  • Account Creation via prompt=create.
  • Prompt combinations prompt=select_account+consent and prompt=login+consent
  • Tests: From 9 to 139 (including separate tests per endpoint)

Blocking PRs (I can easily remove it from the commit history so PR is addition only)


Status updates

  • OIDC compatable
  • OAuth2.1 endpoints
  • Migration guide if utilized the oidc-provider plugin
  • Plugin page Doc
  • trustedClients logic

Replaces


Addresses


Summary by cubic

Adds an OAuth 2.1 provider plugin with secure defaults and full OAuth/OIDC endpoints, including userinfo and RP-initiated logout. Adds a resource-server client and moves verifyAccessToken to core for server-side token checks.

  • New Features

    • Endpoints: /oauth2/authorize, /oauth2/token, /oauth2/register, /oauth2/introspect (RFC 7662), /oauth2/revoke (RFC 7009), metadata (RFC 8414, OIDC), well-known auth and protected resource metadata (server-only), /userinfo, RP-initiated logout, /oauth2/consent, /oauth2/continue, server-only client CRUD endpoints, a public client info endpoint, and user consent management endpoints (get/list/update/delete).
    • Grants: authorization_code (PKCE), client_credentials, refresh_token. Implicit and password not supported.
    • Client management: server-only CRUD and secret rotation; dynamic registration; per-client skip consent; organization/reference support.
    • Security: hashed tokens, refresh token replay prevention, per-scope expirations, optional opaque tokens; JWT signing/JWKS; core verifyAccessToken helper, resource-server client, and MCP handler; validAudiences support.
    • Consent and account selection: prompt=select_account, prompt=create, and a post-login consent flow with organization/team selection; supports combined prompts like "login consent" and "select_account consent".
  • Migration

    • If migrating from the OIDC provider:
      • Defaults remain: accessTokenExpiresIn 1hr, idTokenExpiresIn 10h, refreshTokenExpiresIn 30d; add scopeExpirations if needed.
      • Tokens are hashed by default; configure prefixes as needed (opaqueAccessTokenPrefix, clientSecretPrefix, refreshTokenPrefix).
      • Use authServerMetadata and oidcServerMetadata to build well-known endpoints (server-only); set issuer/audience and JWKS. Add protected resource metadata if you verify tokens server-side.
      • defaultScope replaced by clientRegistrationDefaultScopes (array).
      • Map client_id to id in your adapter (recommended).
      • Use the new oauthProvider client and oauthProviderResourceClient; provide loginPage and consentPage routes. verifyAccessToken is now in better-auth/oauth2.
      • MCP and OIDC plugins are deprecated; switch to OAuth Provider.

Written for commit 1defa68427. Summary will update automatically on new commits.


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/better-auth/better-auth/pull/4163 **Author:** [@dvanmali](https://github.com/dvanmali) **Created:** 8/22/2025 **Status:** ✅ Merged **Merged:** 12/22/2025 **Merged by:** [@dvanmali](https://github.com/dvanmali) **Base:** `canary` ← **Head:** `oauth2.1` --- ### 📝 Commits (7) - [`7eb90a9`](https://github.com/better-auth/better-auth/commit/7eb90a95f63620e0879abe732b90016a845bd2c7) feat: oauth 2.1 provider plugin - [`3eade9c`](https://github.com/better-auth/better-auth/commit/3eade9cb3632b58a5add9441d1e887c810511813) feat: OIDC prompt='create' and account registration callbacks - [`ed3b692`](https://github.com/better-auth/better-auth/commit/ed3b69262afff9565529b46a4446fd8602d00dc6) chore: restore versioning - [`8d42a06`](https://github.com/better-auth/better-auth/commit/8d42a06ed55d94d9369986973326269c96444dde) docs: suggestions and update schema - [`5b522ff`](https://github.com/better-auth/better-auth/commit/5b522ff51c71fcaedf2301f7a2285cccef688c5b) chore: pnpm-lock.yaml only - [`d2499da`](https://github.com/better-auth/better-auth/commit/d2499da09cf6a7975c95b93b2b8a7063d722a861) chore: oauth consent demo move - [`1defa68`](https://github.com/better-auth/better-auth/commit/1defa6842792fbd1708a0990564c6b576a91e447) chore: bump version ### 📊 Changes **70 files changed** (+18739 additions, -62 deletions) <details> <summary>View changed files</summary> ➕ `demo/nextjs/app/(auth)/oauth/consent/consent-buttons.tsx` (+47 -0) ➕ `demo/nextjs/app/(auth)/oauth/consent/page.tsx` (+140 -0) ➕ `demo/nextjs/app/(auth)/oauth/select-account/account-button.tsx` (+69 -0) ➕ `demo/nextjs/app/(auth)/oauth/select-account/page.tsx` (+37 -0) ➕ `demo/nextjs/app/(auth)/oauth/select-organization/org-buttons.tsx` (+75 -0) ➕ `demo/nextjs/app/(auth)/oauth/select-organization/page.tsx` (+54 -0) ➕ `demo/nextjs/app/.well-known/oauth-authorization-server/route.ts` (+18 -0) ➕ `demo/nextjs/app/.well-known/oauth-protected-resource/api/mcp/route.ts` (+22 -0) ➕ `demo/nextjs/app/.well-known/oauth-protected-resource/route.ts` (+20 -0) ➕ `demo/nextjs/app/.well-known/openid-configuration/route.ts` (+18 -0) 📝 `demo/nextjs/app/api/auth/[...all]/route.ts` (+42 -1) ➕ `demo/nextjs/app/api/mcp/route.ts` (+90 -0) 📝 `demo/nextjs/app/page.tsx` (+4 -0) 📝 `demo/nextjs/lib/auth-client.ts` (+2 -0) 📝 `demo/nextjs/lib/auth.ts` (+104 -1) ➕ `demo/nextjs/lib/server-client.ts` (+7 -0) 📝 `demo/nextjs/package.json` (+3 -0) 📝 `docs/components/sidebar-content.tsx` (+23 -0) 📝 `docs/content/docs/plugins/mcp.mdx` (+4 -0) ➕ `docs/content/docs/plugins/oauth-provider.mdx` (+1830 -0) _...and 50 more files_ </details> ### 📄 Description # oAuth 2.1 Provider An upgrade to oidc-provider plugin that makes it oauth2.1 compliant and has a configuration that is secure by default. Plans for the deprecation of oidc-provider plugin due to many inherent flaws in its design. Internally, plugin functions now share logic, providing for better future extensibility if new `code_grants` need to be written or user/client jwt or opaque tokens need to be written. Furthermore, as an oAuth 2.1 provider, it provides logic valid for an MCP server. When using the scope "openid" (optional, enabled by default), the server acts like an OpenId server able to issue id tokens and provides a `/userinfo` endpoint. **Features** - OAuth 2.1 by default - Properly supports authorization_code, refresh_token, and client_credentials grants - PKCE by default (removes `plain` completely) - Public and confidential client registration - JWT plugin is required by default, but can be disabled using `disableJWTPlugin` flag - Access tokens can now be received in JWT verifiable format using the `resource` parameter (ie JWT `aud` field) - Id tokens are still verifiable by JWKS when using JWT Plugin, or clientSecret if disabled. Fixes issue to prevent public clients when `disableJWTPlugin: true` from obtaining id tokens directly even when they shouldn't be allowed an id token and should use `/userinfo` instead. - Protects `/userinfo` with scope check - Separates Refresh Token and Access token on database schema to allow multiple access tokens per refresh and multiple refresh tokens per login session. - `oauthAccessToken` strictly deals with opaque tokens - Opaque tokens are given only when resource parameter (aka audience) is not provided - Option to Encode and Decode refresh tokens - `allowDynamicClientRegistration` with `allowUnauthenticatedClientRegistration` flags - Separation of default expiration times - Proper creation of public and confidential clients - Prevents misconfiguration between `.well-known/openid-configuration` endpoint and plugin settings - `scopeExpirations` to assign scopes specific expiration - Custom claims through separated functions: `customAccessTokenClaims`, `customIdTokenClaims`, and `customUserInfoClaims` - Organizational support through `activeOrganizationalId` on a session such as through the `organizational` plugin. Attaches to oAuthClient via `reference_id`. - Rp-initiated logout - Account Selection via `prompt=select_account`. - Account Creation via `prompt=create`. - Prompt combinations `prompt=select_account+consent` and `prompt=login+consent` - Tests: From 9 to 139 (including separate tests per endpoint) --- Blocking PRs (I can easily remove it from the commit history so PR is addition only) - [x] #4161 - [x] #4297 - [x] #4237 - [x] #6111 --- Status updates - [x] OIDC compatable - [x] OAuth2.1 endpoints - [x] Migration guide if utilized the `oidc-provider` plugin - [x] Plugin page Doc - [x] `trustedClients` logic --- Replaces - [x] #3458 --- Addresses - [x] #5459 - [x] #4268 - [x] #4251 - [x] #4275 - [x] #2912, #2726 - [x] #4075 - [x] #4251 - [x] #3071 - [x] #3725 - [x] #2655 - [x] #4624 - [x] #4540 - [x] #4057 - [x] #3300 (only oAuth 2.1 not FAPI) - [x] #2360 - [x] #5025 - [x] #5224 - [x] #4736 - [x] #4594 (removal of prompt entirely) - [x] #2544, #5942 - [x] #5899 - [x] #6737 <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Adds an OAuth 2.1 provider plugin with secure defaults and full OAuth/OIDC endpoints, including userinfo and RP-initiated logout. Adds a resource-server client and moves verifyAccessToken to core for server-side token checks. - **New Features** - Endpoints: /oauth2/authorize, /oauth2/token, /oauth2/register, /oauth2/introspect (RFC 7662), /oauth2/revoke (RFC 7009), metadata (RFC 8414, OIDC), well-known auth and protected resource metadata (server-only), /userinfo, RP-initiated logout, /oauth2/consent, /oauth2/continue, server-only client CRUD endpoints, a public client info endpoint, and user consent management endpoints (get/list/update/delete). - Grants: authorization_code (PKCE), client_credentials, refresh_token. Implicit and password not supported. - Client management: server-only CRUD and secret rotation; dynamic registration; per-client skip consent; organization/reference support. - Security: hashed tokens, refresh token replay prevention, per-scope expirations, optional opaque tokens; JWT signing/JWKS; core verifyAccessToken helper, resource-server client, and MCP handler; validAudiences support. - Consent and account selection: prompt=select_account, prompt=create, and a post-login consent flow with organization/team selection; supports combined prompts like "login consent" and "select_account consent". - **Migration** - If migrating from the OIDC provider: - Defaults remain: accessTokenExpiresIn 1hr, idTokenExpiresIn 10h, refreshTokenExpiresIn 30d; add scopeExpirations if needed. - Tokens are hashed by default; configure prefixes as needed (opaqueAccessTokenPrefix, clientSecretPrefix, refreshTokenPrefix). - Use authServerMetadata and oidcServerMetadata to build well-known endpoints (server-only); set issuer/audience and JWKS. Add protected resource metadata if you verify tokens server-side. - defaultScope replaced by clientRegistrationDefaultScopes (array). - Map client_id to id in your adapter (recommended). - Use the new oauthProvider client and oauthProviderResourceClient; provide loginPage and consentPage routes. verifyAccessToken is now in better-auth/oauth2. - MCP and OIDC plugins are deprecated; switch to OAuth Provider. <sup>Written for commit 1defa6842792fbd1708a0990564c6b576a91e447. Summary will update automatically on new commits.</sup> <!-- End of auto-generated description by cubic. --> --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
GiteaMirror added the pull-request label 2026-04-13 08:57:50 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#13477