oauth

package module
v0.0.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 20, 2025 License: MIT Imports: 22 Imported by: 0

README

oauth-mcp-proxy

OAuth 2.1 authentication library for Go MCP servers.

Minimal server-side integration (3 lines of Go code) + deployment configuration.

oauthOption, _ := oauth.WithOAuth(mux, &oauth.Config{Provider: "okta", ...})
mcpServer := server.NewMCPServer("My Server", "1.0.0", oauthOption)
// Server-side OAuth complete. Also need: provider setup + deployment config + client config.

GitHub Workflow Status Go Version Go Report Card Go Reference GitHub Release


Complete Setup Overview

graph TD
    subgraph "1. OAuth Provider Setup"
        A[Create OAuth App<br/>Okta/Google/Azure]
        A --> B[Get ClientID<br/>Get ClientSecret]
    end

    subgraph "2. Server Integration"
        C[Add 3 Lines Go Code<br/>WithOAuth]
        D[Configure Deployment<br/>Helm/env vars]
        C --> D
    end

    subgraph "3. Client Configuration"
        E[Client discovers<br/>via .well-known endpoints]
        F[Or manual config<br/>claude_desktop_config.json]
        E -.->|Auto| G[Client Ready]
        F -.->|Manual| G
    end

    B --> C
    D --> E
    D --> F

    style A fill:#ffe5e5
    style C fill:#e1f5ff
    style G fill:#d4edda

What you need:

  1. OAuth provider configured (one-time setup)
  2. Server code updated (3 lines)
  3. Deployment configured (environment variables / Helm)
  4. Client configured (auto-discovery or manual)

Architecture

graph LR
    Client[MCP Client] -->|HTTP + Bearer Token| Server[Your MCP Server]
    Server -->|1. Extract Token| OAuth[oauth-mcp-proxy]
    OAuth -->|2. Validate| Provider[OAuth Provider<br/>Okta/Google/Azure]
    OAuth -->|3. Add User to Context| Tools[Your MCP Tools]

    style OAuth fill:#e1f5ff
    style Tools fill:#d4edda

What oauth-mcp-proxy does:

  1. Extracts tokens from HTTP requests
  2. Validates against OAuth provider (with caching)
  3. Adds authenticated user to context
  4. Protects all your tools automatically

Authentication Flow

sequenceDiagram
    participant C as MCP Client
    participant S as Your Server
    participant O as oauth-mcp-proxy
    participant P as OAuth Provider

    C->>S: POST /mcp<br/>Header: Bearer token
    S->>O: Extract token from context

    alt Token in cache
        O->>O: Return cached user (< 5ms)
    else Token not cached
        O->>P: Validate token (JWKS/OIDC)
        P->>O: Token valid + claims
        O->>O: Cache for 5 min
    end

    O->>S: Add User to context
    S->>C: Execute tool with auth context

    Note over O: Token caching saves<br/>~95ms per request

Quick Start

Prerequisites: OAuth app created in your provider (Okta/Google/Azure). See Provider Guides.

1. Install Library
go get github.com/tuannvm/oauth-mcp-proxy
2. Add to Server Code (3 lines)
import oauth "github.com/tuannvm/oauth-mcp-proxy"

mux := http.NewServeMux()
oauthOption, _ := oauth.WithOAuth(mux, &oauth.Config{
    Provider: "okta",                        // or "hmac", "google", "azure"
    Issuer:   os.Getenv("OAUTH_ISSUER"),     // From environment
    Audience: os.Getenv("OAUTH_AUDIENCE"),
})
mcpServer := mcpserver.NewMCPServer("Server", "1.0.0", oauthOption)
3. Configure Deployment

Environment variables (Kubernetes ConfigMap, docker-compose, etc.):

OAUTH_PROVIDER=okta
OAUTH_ISSUER=https://company.okta.com
OAUTH_AUDIENCE=api://my-server
# For proxy mode: OAUTH_CLIENT_ID, OAUTH_CLIENT_SECRET, etc.

See: Configuration Guide

4. Configure Client

Auto-discovery (Claude Desktop):

{"mcpServers": {"my-server": {"url": "https://your-server.com/mcp"}}}

Client auto-discovers OAuth via .well-known endpoints.

See: Client Setup Guide

Complete example: examples/simple/


Providers

graph TD
    A[oauth-mcp-proxy] --> B[HMAC<br/>Shared Secret]
    A --> C[Okta<br/>Enterprise SSO]
    A --> D[Google<br/>Workspace]
    A --> E[Azure AD<br/>Microsoft 365]

    B -.->|Testing/Dev| F[Your Choice]
    C -.->|Enterprise| F
    D -.->|Google Users| F
    E -.->|MS Users| F

    style A fill:#e1f5ff
    style F fill:#d4edda
Provider Best For Setup Guide
HMAC Testing, development Setup
Okta Enterprise SSO Setup
Google Google Workspace Setup
Azure AD Microsoft 365 Setup

Quick config examples: See Configuration Guide


Features

  • 3-line integration - WithOAuth() handles everything
  • Token caching - 5-minute cache, <5ms validation
  • Security hardened - PKCE, redirect validation, defense-in-depth
  • Pluggable logging - Integrate with zap, logrus, slog
  • Instance-scoped - No globals, thread-safe
  • OAuth 2.1 - Latest spec compliance

Documentation

📖 Setup Guides:

📚 Reference:

🎯 Examples:

📋 Planning:


Status

Current Release: v0.0.1 (Preview)

Phase Status
0-5 Complete
6 ⏳ Next: mcp-trino migration

Stable Release (v0.1.0): After Phase 6 validation complete


Dependencies

4 well-maintained, industry-standard libraries:

  • github.com/mark3labs/mcp-go v0.41.1 - MCP protocol
  • github.com/coreos/go-oidc/v3 v3.16.0 - OIDC validation
  • github.com/golang-jwt/jwt/v5 v5.3.0 - JWT validation
  • golang.org/x/oauth2 v0.32.0 - OAuth flows

All required for core functionality.


Contributing

Not accepting contributions during extraction phase. After v0.1.0 release, contributions welcome!

Report issues: GitHub Issues


License

MIT License - See LICENSE

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func CreateHTTPContextFunc

func CreateHTTPContextFunc() func(context.Context, *http.Request) context.Context

CreateHTTPContextFunc creates an HTTP context function that extracts OAuth tokens from Authorization headers. Use with mcpserver.WithHTTPContextFunc() to enable token extraction from HTTP requests.

Example:

streamableServer := mcpserver.NewStreamableHTTPServer(
    mcpServer,
    mcpserver.WithHTTPContextFunc(oauth.CreateHTTPContextFunc()),
)

This extracts "Bearer <token>" from Authorization header and adds it to context via WithOAuthToken(). The OAuth middleware then retrieves it via GetOAuthToken().

func CreateRequestAuthHook deprecated

func CreateRequestAuthHook(validator provider.TokenValidator) func(context.Context, interface{}, interface{}) error

CreateRequestAuthHook creates a server-level authentication hook for all MCP requests.

Deprecated: This function cannot propagate context changes due to its signature limitation. Use WithOAuth() instead, which properly handles context propagation via tool-level middleware.

This function is a no-op that always returns nil. Authentication happens at the tool level via Server.Middleware() which can properly propagate the authenticated user in context.

func GetOAuthToken

func GetOAuthToken(ctx context.Context) (string, bool)

GetOAuthToken extracts an OAuth token from the context

func OAuthMiddleware deprecated

func OAuthMiddleware(validator provider.TokenValidator, enabled bool) func(server.ToolHandlerFunc) server.ToolHandlerFunc

OAuthMiddleware creates an authentication middleware (legacy function for compatibility).

Deprecated: Use WithOAuth() for new code. This function creates a temporary Server instance for each call and doesn't support custom logging. Kept for backward compatibility only.

Modern usage:

oauthOption, _ := oauth.WithOAuth(mux, &oauth.Config{...})
mcpServer := server.NewMCPServer("name", "1.0.0", oauthOption)

func SetupOAuth deprecated

func SetupOAuth(cfg *Config) (provider.TokenValidator, error)

SetupOAuth initializes OAuth validation and sets up OAuth configuration.

Deprecated: Use WithOAuth() for new code, which provides complete OAuth setup including middleware and HTTP handlers. This function only creates a validator and requires manual wiring.

Modern usage:

oauthOption, _ := oauth.WithOAuth(mux, &oauth.Config{...})
mcpServer := server.NewMCPServer("name", "1.0.0", oauthOption)

func WithOAuth

func WithOAuth(mux *http.ServeMux, cfg *Config) (mcpserver.ServerOption, error)

WithOAuth returns a server option that enables OAuth authentication This is the composable API for mcp-go v0.41.1

Usage:

mux := http.NewServeMux()
oauthOption, err := oauth.WithOAuth(mux, &oauth.Config{...})
mcpServer := server.NewMCPServer("Server", "1.0.0", oauthOption)

This function: - Creates OAuth server internally - Registers OAuth HTTP endpoints on mux - Returns middleware as server option

Note: You must also configure HTTPContextFunc to extract the OAuth token from HTTP headers. Use CreateHTTPContextFunc() helper.

func WithOAuthToken

func WithOAuthToken(ctx context.Context, token string) context.Context

WithOAuthToken adds an OAuth token to the context

Types

type CachedToken

type CachedToken struct {
	User      *User
	ExpiresAt time.Time
}

CachedToken represents a cached token validation result

type Config

type Config struct {
	// OAuth settings
	Mode         string // "native" or "proxy"
	Provider     string // "hmac", "okta", "google", "azure"
	RedirectURIs string // Redirect URIs (single or comma-separated)

	// OIDC configuration
	Issuer       string
	Audience     string
	ClientID     string
	ClientSecret string

	// Server configuration
	ServerURL string // Full URL of the MCP server

	// Security
	JWTSecret []byte // For HMAC provider and state signing

	// Optional - Logging
	// Logger allows custom logging implementation. If nil, uses default logger
	// that outputs to log.Printf with level prefixes ([INFO], [ERROR], etc.).
	// Implement the Logger interface (Debug, Info, Warn, Error methods) to
	// integrate with your application's logging system (e.g., zap, logrus).
	Logger Logger
}

Config holds OAuth configuration

func (*Config) Validate

func (c *Config) Validate() error

Validate validates the configuration

type Logger

type Logger interface {
	Debug(msg string, args ...interface{}) // Debug-level logging for detailed troubleshooting
	Info(msg string, args ...interface{})  // Info-level logging for normal OAuth operations
	Warn(msg string, args ...interface{})  // Warn-level logging for security violations
	Error(msg string, args ...interface{}) // Error-level logging for OAuth failures
}

Logger interface for pluggable logging. Implement this interface to integrate oauth-mcp-proxy with your application's logging system (e.g., zap, logrus, slog). If not provided in Config, a default logger using log.Printf will be used.

Example:

type MyLogger struct{ logger *zap.Logger }
func (l *MyLogger) Info(msg string, args ...interface{}) {
    l.logger.Sugar().Infof(msg, args...)
}
// ... implement Debug, Warn, Error

cfg := &oauth.Config{
    Provider: "okta",
    Logger: &MyLogger{logger: zapLogger},
}

type OAuth2Config

type OAuth2Config struct {
	Enabled      bool
	Mode         string // "native" or "proxy"
	Provider     string
	RedirectURIs string

	// OIDC configuration
	Issuer       string
	Audience     string
	ClientID     string
	ClientSecret string

	// Server configuration
	MCPHost string
	MCPPort string
	Scheme  string

	// MCPURL is the full URL of the MCP server, used for the resource endpoint in the OAuth 2.0 Protected Resource Metadata endpoint
	MCPURL string

	// Server version
	Version string
	// contains filtered or unexported fields
}

OAuth2Config holds OAuth2 configuration

func NewOAuth2ConfigFromConfig

func NewOAuth2ConfigFromConfig(cfg *Config, version string) *OAuth2Config

NewOAuth2ConfigFromConfig creates OAuth2 config from generic Config

type OAuth2Handler

type OAuth2Handler struct {
	// contains filtered or unexported fields
}

OAuth2Handler handles OAuth2 flows using the standard library

func CreateOAuth2Handler

func CreateOAuth2Handler(cfg *Config, version string, logger Logger) *OAuth2Handler

CreateOAuth2Handler creates a new OAuth2 handler for HTTP endpoints

func NewOAuth2Handler

func NewOAuth2Handler(cfg *OAuth2Config, logger Logger) *OAuth2Handler

NewOAuth2Handler creates a new OAuth2 handler using the standard library

func (*OAuth2Handler) GetAuthorizationServerMetadata

func (h *OAuth2Handler) GetAuthorizationServerMetadata() map[string]interface{}

GetAuthorizationServerMetadata returns the OAuth 2.0 Authorization Server Metadata with conditional responses based on OAuth mode

func (*OAuth2Handler) GetConfig

func (h *OAuth2Handler) GetConfig() *OAuth2Config

GetConfig returns the OAuth2 configuration

func (*OAuth2Handler) HandleAuthorizationServerMetadata

func (h *OAuth2Handler) HandleAuthorizationServerMetadata(w http.ResponseWriter, r *http.Request)

HandleAuthorizationServerMetadata handles the standard OAuth 2.0 Authorization Server Metadata endpoint

func (*OAuth2Handler) HandleAuthorize

func (h *OAuth2Handler) HandleAuthorize(w http.ResponseWriter, r *http.Request)

HandleAuthorize handles OAuth2 authorization requests with PKCE

func (*OAuth2Handler) HandleCallback

func (h *OAuth2Handler) HandleCallback(w http.ResponseWriter, r *http.Request)

HandleCallback handles OAuth2 callback

func (*OAuth2Handler) HandleCallbackRedirect

func (h *OAuth2Handler) HandleCallbackRedirect(w http.ResponseWriter, r *http.Request)

HandleCallbackRedirect handles the /callback redirect for Claude Code compatibility

func (*OAuth2Handler) HandleJWKS

func (h *OAuth2Handler) HandleJWKS(w http.ResponseWriter, r *http.Request)

HandleJWKS handles the JWKS endpoint for proxy mode

func (*OAuth2Handler) HandleMetadata

func (h *OAuth2Handler) HandleMetadata(w http.ResponseWriter, r *http.Request)

HandleMetadata handles the legacy OAuth metadata endpoint for MCP compliance

func (*OAuth2Handler) HandleOIDCDiscovery

func (h *OAuth2Handler) HandleOIDCDiscovery(w http.ResponseWriter, r *http.Request)

HandleOIDCDiscovery handles the OIDC discovery endpoint for MCP client compatibility

func (*OAuth2Handler) HandleProtectedResourceMetadata

func (h *OAuth2Handler) HandleProtectedResourceMetadata(w http.ResponseWriter, r *http.Request)

HandleProtectedResourceMetadata handles the OAuth 2.0 Protected Resource Metadata endpoint

func (*OAuth2Handler) HandleRegister

func (h *OAuth2Handler) HandleRegister(w http.ResponseWriter, r *http.Request)

HandleRegister handles OAuth dynamic client registration for mcp-remote

func (*OAuth2Handler) HandleToken

func (h *OAuth2Handler) HandleToken(w http.ResponseWriter, r *http.Request)

HandleToken handles OAuth2 token exchange

type Server

type Server struct {
	// contains filtered or unexported fields
}

Server represents an OAuth authentication server instance. Each Server maintains its own token cache and validator, allowing multiple independent OAuth configurations in the same application.

Create using NewServer(). Access middleware via Middleware() and register HTTP endpoints via RegisterHandlers().

func NewServer

func NewServer(cfg *Config) (*Server, error)

NewServer creates a new OAuth server with the given configuration. Validates configuration, initializes provider-specific token validator, and creates instance-scoped token cache.

Example:

server, err := oauth.NewServer(&oauth.Config{
    Provider: "okta",
    Issuer:   "https://company.okta.com",
    Audience: "api://my-server",
})

Most users should use WithOAuth() instead, which wraps NewServer() and automatically registers handlers and middleware.

func (*Server) Middleware

func (s *Server) Middleware() func(server.ToolHandlerFunc) server.ToolHandlerFunc

Middleware returns an authentication middleware for MCP tools. Validates OAuth tokens, caches results, and adds authenticated user to context.

The middleware:

  1. Extracts OAuth token from context (set by CreateHTTPContextFunc)
  2. Checks token cache (5-minute TTL)
  3. Validates token using configured provider if not cached
  4. Adds User to context via userContextKey
  5. Passes request to tool handler with authenticated context

Use GetUserFromContext(ctx) in tool handlers to access authenticated user.

Note: WithOAuth() returns this middleware wrapped as mcpserver.ServerOption. Only call directly if using NewServer() for advanced use cases.

func (*Server) RegisterHandlers

func (s *Server) RegisterHandlers(mux *http.ServeMux)

RegisterHandlers registers OAuth HTTP endpoints on the provided mux. Endpoints registered:

  • /.well-known/oauth-authorization-server - OAuth 2.0 metadata (RFC 8414)
  • /.well-known/oauth-protected-resource - Resource metadata
  • /.well-known/jwks.json - JWKS keys
  • /.well-known/openid-configuration - OIDC discovery
  • /oauth/authorize - Authorization endpoint (proxy mode)
  • /oauth/callback - Callback handler (proxy mode)
  • /oauth/token - Token exchange (proxy mode)
  • /oauth/register - Dynamic client registration

Note: WithOAuth() calls this automatically. Only call directly if using NewServer() for advanced use cases.

type TokenCache

type TokenCache struct {
	// contains filtered or unexported fields
}

TokenCache stores validated tokens to avoid re-validation

type User

type User = provider.User

Re-export User from provider for backwards compatibility

func GetUserFromContext

func GetUserFromContext(ctx context.Context) (*User, bool)

GetUserFromContext extracts the authenticated user from context. Returns the User and true if authentication succeeded, or nil and false otherwise.

Example:

func toolHandler(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
    user, ok := oauth.GetUserFromContext(ctx)
    if !ok {
        return nil, fmt.Errorf("authentication required")
    }
    // Use user.Subject, user.Email, user.Username
    return mcp.NewToolResultText("Hello, " + user.Username), nil
}

Directories

Path Synopsis
examples
embedded command
simple command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL