ConduitMcp.Plugs.OAuth (ConduitMCP v0.9.0)

Copy Markdown View Source

OAuth 2.1 authentication plug for MCP servers.

Validates JWT Bearer tokens against a configured authorization server. Implements the MCP specification's OAuth 2.1 Resource Server requirements.

Features

  • JWT signature verification via pluggable key providers
  • Issuer and audience validation
  • Token expiration checking
  • Scope extraction and enforcement
  • WWW-Authenticate headers per RFC 9728
  • Protected Resource Metadata endpoint support

Configuration

# Basic OAuth with JWKS auto-discovery
{ConduitMcp.Transport.StreamableHTTP,
  server_module: MyServer,
  auth: [
    strategy: :oauth,
    issuer: "https://auth.example.com",
    audience: "https://mcp.example.com",
    scopes_supported: ["read", "write", "admin"],
    key_provider: {ConduitMcp.OAuth.KeyProvider.JWKS,
      jwks_uri: "https://auth.example.com/.well-known/jwks.json"}
  ]}

# Static keys for testing
{ConduitMcp.Transport.StreamableHTTP,
  server_module: MyServer,
  auth: [
    strategy: :oauth,
    issuer: "test-issuer",
    audience: "test-audience",
    key_provider: {ConduitMcp.OAuth.KeyProvider.Static,
      keys: [test_key_map]}
  ]}

Token Claims

After successful validation, the token claims are stored in conn.assigns[:oauth_claims] and the scopes in conn.assigns[:oauth_scopes].

Summary

Functions

Sends a 403 Forbidden response with insufficient_scope error. Used by the handler when a tool/resource requires a scope the token doesn't have.

Checks if the authenticated request has the required scope. Returns true if the scope is present, false otherwise.

Checks if the authenticated request has all required scopes.

Functions

forbidden(conn, opts, required_scopes)

Sends a 403 Forbidden response with insufficient_scope error. Used by the handler when a tool/resource requires a scope the token doesn't have.

has_scope?(conn, required_scope)

Checks if the authenticated request has the required scope. Returns true if the scope is present, false otherwise.

has_scopes?(conn, required_scopes)

Checks if the authenticated request has all required scopes.