Skip to content

feat(auth): DCR hooks, introspection auth, and prehandler fixes#100

Open
getlarge wants to merge 3 commits intoplatformatic:mainfrom
getlarge:feat/dcr-hooks-and-introspection-auth
Open

feat(auth): DCR hooks, introspection auth, and prehandler fixes#100
getlarge wants to merge 3 commits intoplatformatic:mainfrom
getlarge:feat/dcr-hooks-and-introspection-auth

Conversation

@getlarge
Copy link

Summary

Adds DCR proxy hooks and introspection authentication support for Ory Hydra integration.

⚠️ Dependency: This PR depends on #97 (OIDC Discovery) and should be merged after it.

Changes

1. Skip /oauth/register in auth prehandler

DCR endpoint must be accessible before client has credentials.

2. Add introspectionAuth configuration

Supports bearer (API key), basic (client credentials), or none for token introspection authentication.

tokenValidation: {
  introspectionEndpoint: 'https://ory.example.com/admin/oauth2/introspect',
  introspectionAuth: { type: 'bearer', token: 'api-key' }
}

3. Add dcrHooks for DCR proxy pattern

Enables MCP server to act as a DCR proxy with request/response transformation.

dcrHooks: {
  upstreamEndpoint: 'https://ory.example.com/oauth2/register',
  onResponse: async (response) => {
    // Clean empty fields that break Claude Code's Zod validation
    if (response.client_uri === '') delete response.client_uri;
    return response;
  }
}

Breaking Change

/oauth/register returns 501 unless dcrHooks is configured. This prevents infinite loops when OIDC discovery points back to the MCP server.

Tests

  • ✅ All 45 OAuth/token-validator tests pass
  • ✅ New tests for introspectionAuth (bearer, basic, none)
  • ✅ New tests for dcrHooks (501 without config, proxy with hooks)

Related

🤖 Generated with Claude Code

getlarge and others added 3 commits January 25, 2026 16:22
…on tests

The MCP SDK types use discriminated unions (e.g., text | image content).
TypeScript requires type narrowing before accessing type-specific properties.

This fixes typecheck failures introduced by SDK type changes.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add OIDC discovery to fetch endpoints from /.well-known/openid-configuration
  with 5-minute caching and fallback to default /oauth/* paths
- Include redirect_uri in authorization request (required for OIDC 1.0)
- Pass redirect_uri to token exchange (must match authorization request)
- Skip /oauth/callback in auth prehandler
- Add excludedPaths option for custom routes to bypass authorization
  (e.g., health checks)

This enables compatibility with OAuth providers like Ory Hydra that use
non-standard endpoint paths (e.g., /oauth2/auth instead of /oauth/authorize).

Closes platformatic#95

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit adds several OAuth/DCR improvements:

Patch 3.1: Skip /oauth/register in auth prehandler
- DCR endpoint must be accessible before client has credentials
- Fixes chicken-and-egg problem with dynamic registration

Patch 3.2: Add introspectionAuth configuration
- Supports bearer (API key), basic (client credentials), or none
- Required for Ory Hydra admin introspection endpoint
- Backwards compatible - defaults to no auth header

Patch 3.3: Pass DCR request body through to dynamicClientRegistration
- Client metadata is now merged with defaults (client wins)
- Allows clients to specify their own redirect_uris, client_name, etc.

Patch 4: Add dcrHooks for DCR proxy pattern
- upstreamEndpoint: Required, bypasses OIDC discovery to avoid loops
- onRequest: Hook to transform/enrich DCR request
- onResponse: Hook to clean/transform DCR response (e.g., remove empty fields)
- Returns 501 when not configured (prevents infinite loop)

Breaking change: /oauth/register now returns 501 unless dcrHooks is configured.
This prevents infinite loops when OIDC discovery points back to the MCP server.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant