[PR #3091] [MERGED] feat(mcp): add support for public clients with PKCE authentication #21541

Closed
opened 2026-04-15 20:25:50 -05:00 by GiteaMirror · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/better-auth/better-auth/pull/3091
Author: @pekastel
Created: 6/19/2025
Status: Merged
Merged: 7/17/2025
Merged by: @Bekacru

Base: v1.3Head: fix/2813-pkce-public-clients


📝 Commits (10+)

  • bb6e947 feat(mcp): add support for public clients with PKCE authentication
  • 68ee384 style: format code with prettier and fix trailing commas
  • da8ac14 fix: resolve TypeScript errors in MCP plugin and tests
  • 21bd53d fix: resolve TypeScript, Vitest, and CI compatibility issues
  • d79c368 OpenAPI Schema Contract Fixed
  • bd3e9a3 fix: resolve lint
  • 3646c5d fix: ensure OAuth 2.0 spec compliance for public client registration
  • 236d7a3 update docs
  • ad5cd66 remove any
  • ed6f31d dont return secret on public client oidc

📊 Changes

7 files changed (+624 additions, -69 deletions)

View changed files

📝 docs/content/docs/plugins/oidc-provider.mdx (+3 -2)
📝 packages/better-auth/src/plugins/mcp/index.ts (+78 -47)
packages/better-auth/src/plugins/mcp/mcp.test.ts (+511 -0)
📝 packages/better-auth/src/plugins/oidc-provider/index.ts (+21 -13)
📝 packages/better-auth/src/plugins/oidc-provider/oidc.test.ts (+5 -5)
📝 packages/better-auth/src/plugins/oidc-provider/schema.ts (+1 -0)
📝 packages/better-auth/src/plugins/oidc-provider/types.ts (+5 -2)

📄 Description

Summary

Adds comprehensive support for OAuth 2.0 public clients in the MCP plugin, enabling PKCE-only authentication without
client secrets. This resolves authentication issues with Claude.ai and other public OAuth clients that use PKCE
(Proof Key for Code Exchange) as specified in RFC 7636 and RFC 8252.

Problem

The current MCP plugin only supports confidential OAuth clients that require client_secret for authentication.
This prevents public clients (mobile apps, SPAs, CLI tools like Claude.ai) from authenticating properly, as they:

  • Cannot securely store client secrets
  • Must use PKCE instead of client secrets for security
  • Need token_endpoint_auth_method: "none" support

This was causing authentication failures for legitimate OAuth clients.

Solution

Implemented conditional client authentication based on client type:

Public Clients (PKCE-only)

  • Registered with token_endpoint_auth_method: "none"
  • Authenticate using PKCE code_verifier instead of client_secret
  • Store empty/null client_secret in database
  • Automatically assigned type: "public"

Confidential Clients (existing behavior)

  • Continue using client_secret authentication
  • Maintain full backward compatibility
  • No changes to existing workflows

Implementation Details

Client Registration

  • Added client type detection logic based on token_endpoint_auth_method
  • Public clients get client_secret: "" and type: "public"
  • Confidential clients continue with existing behavior

Token Authentication

  • Added conditional validation in /mcp/token endpoint
  • Public clients: validate PKCE code_verifier (required)
  • Confidential clients: validate client_secret (required)
  • Enhanced error messages for better debugging

OAuth Discovery

  • Added "none" to token_endpoint_auth_methods_supported
  • Updated metadata to advertise public client support

Database Schema

  • Made clientSecret optional in OIDC schema
  • Updated client type definitions to include "public"

Testing

Added comprehensive test suite with 9 test cases:

  • OAuth discovery metadata endpoint validation
  • Public client registration with token_endpoint_auth_method: "none"
  • Confidential client registration (backward compatibility)
  • Public client PKCE-only authentication flow
  • PKCE validation and error handling
  • Token refresh flow validation
  • UserInfo endpoint functionality
  • ID token generation and processing
  • Error handling for invalid requests

Breaking Changes

None. This change is fully backward compatible:

  • Existing confidential clients continue to work unchanged
  • No modifications to existing API contracts
  • Database migrations handle optional clientSecret

Security Considerations

  • Public clients must use PKCE (enforced)
  • No relaxation of security for confidential clients
  • Follows OAuth 2.1 and RFC 8252 security recommendations
  • Prevents authentication bypass attempts

Resolves

Fixes #2813 - Support for public OAuth clients using PKCE


🔄 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/3091 **Author:** [@pekastel](https://github.com/pekastel) **Created:** 6/19/2025 **Status:** ✅ Merged **Merged:** 7/17/2025 **Merged by:** [@Bekacru](https://github.com/Bekacru) **Base:** `v1.3` ← **Head:** `fix/2813-pkce-public-clients` --- ### 📝 Commits (10+) - [`bb6e947`](https://github.com/better-auth/better-auth/commit/bb6e947b78479060b33c2320d8bfa0fab1724982) feat(mcp): add support for public clients with PKCE authentication - [`68ee384`](https://github.com/better-auth/better-auth/commit/68ee3840157908922466db1b065f6e1be54ac834) style: format code with prettier and fix trailing commas - [`da8ac14`](https://github.com/better-auth/better-auth/commit/da8ac14f4d56d38d8a8ed356cc143d018a9256ee) fix: resolve TypeScript errors in MCP plugin and tests - [`21bd53d`](https://github.com/better-auth/better-auth/commit/21bd53df47ab439a8abd02aa3bad78a097cbda22) fix: resolve TypeScript, Vitest, and CI compatibility issues - [`d79c368`](https://github.com/better-auth/better-auth/commit/d79c3681f96e4081224fc15eb32c9d52b00a9c00) OpenAPI Schema Contract Fixed - [`bd3e9a3`](https://github.com/better-auth/better-auth/commit/bd3e9a3a096208cf830d5f7c3506703802d674f4) fix: resolve lint - [`3646c5d`](https://github.com/better-auth/better-auth/commit/3646c5d79efb011875da3037bb6053063e7a9bac) fix: ensure OAuth 2.0 spec compliance for public client registration - [`236d7a3`](https://github.com/better-auth/better-auth/commit/236d7a348970dd358e13e0bff4d6177879198e94) update docs - [`ad5cd66`](https://github.com/better-auth/better-auth/commit/ad5cd6668243f4d876a1fd48dff8a4458e2cc7f6) remove any - [`ed6f31d`](https://github.com/better-auth/better-auth/commit/ed6f31d1e119163e47f859d57dce705c856b671a) dont return secret on public client oidc ### 📊 Changes **7 files changed** (+624 additions, -69 deletions) <details> <summary>View changed files</summary> 📝 `docs/content/docs/plugins/oidc-provider.mdx` (+3 -2) 📝 `packages/better-auth/src/plugins/mcp/index.ts` (+78 -47) ➕ `packages/better-auth/src/plugins/mcp/mcp.test.ts` (+511 -0) 📝 `packages/better-auth/src/plugins/oidc-provider/index.ts` (+21 -13) 📝 `packages/better-auth/src/plugins/oidc-provider/oidc.test.ts` (+5 -5) 📝 `packages/better-auth/src/plugins/oidc-provider/schema.ts` (+1 -0) 📝 `packages/better-auth/src/plugins/oidc-provider/types.ts` (+5 -2) </details> ### 📄 Description ## Summary Adds comprehensive support for OAuth 2.0 public clients in the MCP plugin, enabling PKCE-only authentication without client secrets. This resolves authentication issues with Claude.ai and other public OAuth clients that use PKCE (Proof Key for Code Exchange) as specified in RFC 7636 and RFC 8252. ## Problem The current MCP plugin only supports confidential OAuth clients that require `client_secret` for authentication. This prevents public clients (mobile apps, SPAs, CLI tools like Claude.ai) from authenticating properly, as they: - Cannot securely store client secrets - Must use PKCE instead of client secrets for security - Need `token_endpoint_auth_method: "none"` support This was causing authentication failures for legitimate OAuth clients. ## Solution Implemented conditional client authentication based on client type: ### Public Clients (PKCE-only) - Registered with `token_endpoint_auth_method: "none"` - Authenticate using PKCE `code_verifier` instead of `client_secret` - Store empty/null `client_secret` in database - Automatically assigned `type: "public"` ### Confidential Clients (existing behavior) - Continue using `client_secret` authentication - Maintain full backward compatibility - No changes to existing workflows ## Implementation Details ### Client Registration - Added client type detection logic based on `token_endpoint_auth_method` - Public clients get `client_secret: ""` and `type: "public"` - Confidential clients continue with existing behavior ### Token Authentication - Added conditional validation in `/mcp/token` endpoint - Public clients: validate PKCE `code_verifier` (required) - Confidential clients: validate `client_secret` (required) - Enhanced error messages for better debugging ### OAuth Discovery - Added `"none"` to `token_endpoint_auth_methods_supported` - Updated metadata to advertise public client support ### Database Schema - Made `clientSecret` optional in OIDC schema - Updated client type definitions to include `"public"` ## Testing Added comprehensive test suite with 9 test cases: - ✅ OAuth discovery metadata endpoint validation - ✅ Public client registration with `token_endpoint_auth_method: "none"` - ✅ Confidential client registration (backward compatibility) - ✅ Public client PKCE-only authentication flow - ✅ PKCE validation and error handling - ✅ Token refresh flow validation - ✅ UserInfo endpoint functionality - ✅ ID token generation and processing - ✅ Error handling for invalid requests ## Breaking Changes None. This change is fully backward compatible: - Existing confidential clients continue to work unchanged - No modifications to existing API contracts - Database migrations handle optional `clientSecret` ## Security Considerations - Public clients **must** use PKCE (enforced) - No relaxation of security for confidential clients - Follows OAuth 2.1 and RFC 8252 security recommendations - Prevents authentication bypass attempts ## Resolves Fixes #2813 - Support for public OAuth clients using PKCE --- <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-15 20:25: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#21541