Skip to content

Feature: OAuth Middleware Control Configuration #83

@btiernay

Description

@btiernay

Feature: OAuth Middleware Control Configuration

Problem Statement

Currently, XMCP's OAuth implementation automatically applies both the OAuth router and middleware when OAuth is configured. This creates issues because:

  1. Forced Middleware Application: The OAuth middleware is automatically applied alongside the router
  2. No Separation of Concerns: Users cannot use the OAuth router endpoints while implementing custom token verification middleware

Proposed Solution

Add middleware control to the OAuth configuration following XMCP's existing HTTP configuration pattern. The HTTP configuration already supports both boolean and object forms.

Configuration Schema Enhancement

Update the OAuth configuration schema to support the new field:

const oauthConfigSchema = z.object({
    endpoints: oauthEndpointsSchema,
    issuerUrl: z.string(),
    baseUrl: z.string(),
    serviceDocumentationUrl: z.string().optional(),
    pathPrefix: z.string().default("/oauth2"),
    defaultScopes: z.array(z.string()).default(["openid", "profile", "email"]),

    middleware: z.boolean().default(true), // New field to control middleware
});

Factory Implementation

Modify the OAuth factory to conditionally create middleware :

export function createOAuthProxy(config: OAuthProxyConfig): OAuthProxy {
  // ... existing provider and router creation ...
  
  const middleware = config.middleware !== false 
    ? createOAuthMiddleware(provider) 
    : undefined;

  return {
    provider,
    router,
    middleware,
  };
}

Transport Integration

Update the HTTP transport to check for middleware existence before applying it:

if (this.oauthProxy?.middleware) {
  this.app.use(this.oauthProxy.middleware);
}

Usage Examples

Current Behavior (Maintained)

const config: XmcpConfig = {
  experimental: {
    oauth: true, // Enables both router and middleware
  },
};

New Capability

const config: XmcpConfig = {
  experimental: {
    oauth: {
      baseUrl: process.env.BASE_URL!,
      endpoints: {
        authorizationUrl: `https://example.com/authorize`,
        tokenUrl: `https://example.com/oauth/token`,
        registerUrl: `https://example.com/oidc/register`,
      },
      issuerUrl: `https://example.com`,
      middleware: false, // Disable built-in OAuth middleware
    },
  },
};

Benefits

  1. Auth0 Compatibility: Users can disable the problematic OAuth middleware while keeping OAuth router endpoints
  2. Follows XMCP Patterns: Mirrors the existing HTTP configuration pattern
  3. Backward Compatible: Default middleware: true maintains existing behavior
  4. Standards Compliant: Preserves all OAuth 2.0 endpoints for client compatibility
  5. Flexible: Allows custom authentication middleware while reusing XMCP's OAuth infrastructure

Implementation Notes

  • The configuration gets injected at compile time
  • Variable injection logic should handle both boolean and object forms similar to HTTP configuration
  • Type definitions need to be updated to reflect the new union type structure

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions