{"id":36469422,"url":"https://github.com/tuannvm/oauth-mcp-proxy","last_synced_at":"2026-04-03T05:04:05.391Z","repository":{"id":319385650,"uuid":"1078523130","full_name":"tuannvm/oauth-mcp-proxy","owner":"tuannvm","description":"OAuth 2.1 authentication library for Go MCP servers","archived":false,"fork":false,"pushed_at":"2026-02-10T20:22:30.000Z","size":285,"stargazers_count":19,"open_issues_count":4,"forks_count":6,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-02-10T23:39:07.384Z","etag":null,"topics":["authentication","authorization","claude","codex","go-sdk","mcp","mcp-go","oauth"],"latest_commit_sha":null,"homepage":"https://docs.tuannvm.com/oauth-mcp-proxy","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tuannvm.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"docs/SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-10-17T21:53:58.000Z","updated_at":"2026-02-10T20:21:10.000Z","dependencies_parsed_at":null,"dependency_job_id":"aba0a17f-1154-4f2c-ba94-ebb51ba9ce20","html_url":"https://github.com/tuannvm/oauth-mcp-proxy","commit_stats":null,"previous_names":["tuannvm/oauth-mcp-proxy"],"tags_count":12,"template":false,"template_full_name":null,"purl":"pkg:github/tuannvm/oauth-mcp-proxy","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tuannvm%2Foauth-mcp-proxy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tuannvm%2Foauth-mcp-proxy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tuannvm%2Foauth-mcp-proxy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tuannvm%2Foauth-mcp-proxy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tuannvm","download_url":"https://codeload.github.com/tuannvm/oauth-mcp-proxy/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tuannvm%2Foauth-mcp-proxy/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31335194,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-03T04:42:29.251Z","status":"ssl_error","status_checked_at":"2026-04-03T04:42:12.667Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["authentication","authorization","claude","codex","go-sdk","mcp","mcp-go","oauth"],"created_at":"2026-01-12T00:32:35.626Z","updated_at":"2026-04-03T05:04:05.386Z","avatar_url":"https://github.com/tuannvm.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# OAuth MCP proxy\n\nOAuth 2.1 authentication library for Go MCP servers.\n\n**Supports both MCP SDKs:**\n- ✅ `mark3labs/mcp-go`\n- ✅ `modelcontextprotocol/go-sdk` (official)\n\n**One-time setup:** Configure provider + add `WithOAuth()` to your server.\n**Result:** All tools automatically protected with token validation and caching.\n\n### mark3labs/mcp-go\n```go\nimport \"github.com/tuannvm/oauth-mcp-proxy/mark3labs\"\n\noauthServer, oauthOption, _ := mark3labs.WithOAuth(mux, \u0026oauth.Config{\n    Provider: \"okta\",\n    Issuer:   \"https://your-company.okta.com\",\n    Audience: \"api://your-mcp-server\",\n})\n\nmcpServer := server.NewMCPServer(\"Server\", \"1.0.0\", oauthOption)\nstreamable := server.NewStreamableHTTPServer(mcpServer, /*options*/)\nmux.HandleFunc(\"/mcp\", oauthServer.WrapMCPEndpoint(streamable))\n```\n\n### Official SDK\n```go\nimport mcpoauth \"github.com/tuannvm/oauth-mcp-proxy/mcp\"\n\nmcpServer := mcp.NewServer(\u0026mcp.Implementation{...}, nil)\n_, handler, _ := mcpoauth.WithOAuth(mux, cfg, mcpServer)\nhttp.ListenAndServe(\":8080\", handler)\n```\n\n\n[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/tuannvm/oauth-mcp-proxy/test.yml?branch=main\u0026label=Tests\u0026logo=github)](https://github.com/tuannvm/oauth-mcp-proxy/actions/workflows/test.yml)\n[![Go Version](https://img.shields.io/github/go-mod/go-version/tuannvm/oauth-mcp-proxy?logo=go)](https://github.com/tuannvm/oauth-mcp-proxy/blob/main/go.mod)\n[![Go Report Card](https://goreportcard.com/badge/github.com/tuannvm/oauth-mcp-proxy)](https://goreportcard.com/report/github.com/tuannvm/oauth-mcp-proxy)\n[![Go Reference](https://pkg.go.dev/badge/github.com/tuannvm/oauth-mcp-proxy.svg)](https://pkg.go.dev/github.com/tuannvm/oauth-mcp-proxy)\n[![GitHub Release](https://img.shields.io/github/v/release/tuannvm/oauth-mcp-proxy?sort=semver)](https://github.com/tuannvm/oauth-mcp-proxy/releases/latest)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\n---\n\n## Why Use This Library?\n\n- **Dual SDK support** - Works with both mark3labs and official SDKs\n- **Simple integration** - One `WithOAuth()` call protects all tools\n- **Automatic 401 handling** - RFC 6750 compliant error responses with OAuth discovery\n- **Zero per-tool config** - All tools automatically protected\n- **Fast token caching** - 5-min cache with JWT expiry awareness\n- **Security hardened** - State replay protection, DoS prevention, input validation\n- **Built-in rate limiting** - Token-based rate limiter included\n- **CORS support** - OPTIONS pass-through for browser clients\n- **Multiple providers** - HMAC, Okta, Google, Azure AD\n\n---\n\n## How It Works\n\n### Request Flow\n\n```mermaid\nsequenceDiagram\n    participant Client\n    participant MCP Server\n    box lightyellow oauth-mcp-proxy Library\n    participant Middleware\n    participant Cache\n    participant Provider\n    end\n    participant Your Tool Handler\n\n    Client-\u003e\u003eMCP Server: Request + Bearer token\n    MCP Server-\u003e\u003eMiddleware: WithOAuth() intercepts\n\n    alt Token in cache and fresh\n        Middleware-\u003e\u003eCache: Check token hash\n        Cache--\u003e\u003eMiddleware: Return cached user\n    else Token not cached or expired\n        Middleware-\u003e\u003eProvider: Validate token (HMAC/OIDC)\n        Provider--\u003e\u003eMiddleware: User claims\n        Middleware-\u003e\u003eCache: Store user for 5 minutes\n    end\n\n    Middleware-\u003e\u003eYour Tool Handler: Pass request with user in context\n    Your Tool Handler-\u003e\u003eYour Tool Handler: GetUserFromContext(ctx)\n    Your Tool Handler--\u003e\u003eClient: Send response\n```\n\n### Token Validation Flow\n\n```mermaid\nflowchart TB\n    Start([Your MCP Server receives request]) --\u003e Extract[oauth-mcp-proxy: Extract Token]\n    Extract --\u003e Hash[oauth-mcp-proxy: SHA-256 Hash]\n    Hash --\u003e CheckCache{oauth-mcp-proxy: Token Cached?}\n\n    CheckCache --\u003e|Cache Hit| GetUser[oauth-mcp-proxy: Get Cached User]\n    CheckCache --\u003e|Cache Miss| Validate{oauth-mcp-proxy: Validate}\n\n    Validate --\u003e|Valid| Claims[oauth-mcp-proxy: Extract Claims]\n    Validate --\u003e|Invalid| Reject([Return 401])\n\n    Claims --\u003e Store[oauth-mcp-proxy: Cache]\n    Store --\u003e GetUser\n\n    GetUser --\u003e Context[oauth-mcp-proxy: Add User to Context]\n    Context --\u003e Tool[Your Tool Handler: GetUserFromContext]\n    Tool --\u003e Response([Your MCP Server: Return Response])\n\n    style Start fill:#e8f5e9\n    style Extract fill:#fff9c4\n    style Hash fill:#fff9c4\n    style CheckCache fill:#fff9c4\n    style Validate fill:#fff9c4\n    style Claims fill:#fff9c4\n    style Store fill:#fff9c4\n    style GetUser fill:#fff9c4\n    style Context fill:#fff9c4\n    style Tool fill:#e8f5e9\n    style Response fill:#e8f5e9\n    style Reject fill:#ffebee\n```\n\n**What oauth-mcp-proxy does:**\n\n1. Extracts Bearer tokens from HTTP requests\n2. Validates against your OAuth provider (with caching)\n3. Adds authenticated user to request context\n4. All your tools automatically protected\n\n---\n\n## 🔒 Security Features\n\nProduction-ready security hardening built-in:\n\n### State Replay Protection\n- **Timestamp + nonce validation** - States include timestamp and nonce for replay attack prevention\n- **Automatic nonce cleanup** - Expired nonces removed before replay check (prevents memory leaks)\n- **Rolling deploy compatible** - Accepts legacy states without timestamp/nonce for zero-downtime upgrades\n\n### Token Security\n- **JWT expiry-aware caching** - Cache respects token expiration time (uses min(token.expiry, now+5min))\n- **Constant-time HMAC comparison** - Timing attack prevention for signature verification\n- **Secure nonce generation** - Panics on crypto/rand failure (no weak fallback)\n\n### Input Validation \u0026 DoS Prevention\n- **Parameter length limits** - code, state, code_challenge validated to prevent abuse\n- **Request body size limits** - MaxBytesReader on token endpoint (1MB), registration (256KB)\n- **Issuer URL validation** - Enforced HTTPS for non-localhost OIDC providers\n\n### Session Management (Official SDK)\n- **auth.TokenInfo population** - Populates go-sdk auth context for session binding\n- **User-based session tracking** - Prevents session hijacking via user ID verification\n\n### HTTP Security\n- **Security headers** - CSP, X-Frame-Options, X-Content-Type-Options, Cache-Control\n- **CORS support** - OPTIONS pass-through for browser clients\n- **RFC 6750 compliant** - Proper WWW-Authenticate headers with resource_metadata\n\n### Built-in Rate Limiting\n```go\n// Simple token-based rate limiter included\nlimiter := oauth.NewRateLimiter(time.Minute, 100)\nif !limiter.Allow(\"client-ip\") {\n    http.Error(w, \"Rate limit exceeded\", http.StatusTooManyRequests)\n}\n```\n\n---\n\n## Breaking Changes (Security Hardening)\n\n### v1.0.0 → v1.1.0\n\nThe following security improvements introduce **breaking changes**:\n\n**1. Issuer URL Validation (CRITICAL)**\n- **Change**: OIDC providers now enforce HTTPS validation for issuer URLs\n- **Impact**: Invalid issuer URLs will cause `NewServer()` to fail\n- **Migration**: Ensure your `Issuer` config uses HTTPS (or localhost for testing)\n  ```go\n  // ✅ Valid\n  Issuer: \"https://company.okta.com\"\n  Issuer: \"http://localhost:8080\"  // Testing only\n\n  // ❌ Invalid - will fail validation\n  Issuer: \"http://company.okta.com\"  // Not localhost\n  Issuer: \"company.okta.com\"         // Missing scheme\n  ```\n\n**2. State Signing Key Initialization**\n- **Change**: `NewServer()` now panics if state signing key cannot be generated\n- **Impact**: Server startup will fail if crypto/rand fails (should never happen on healthy systems)\n- **Migration**: Ensure your system has a working CSPRNG. No code changes needed.\n\n**3. Nonce Generation Failure Behavior**\n- **Change**: `generateSecureNonce()` now panics instead of falling back to weak timestamp-based nonces\n- **Impact**: OAuth authorization requests will fail if crypto/rand fails\n- **Migration**: Ensure your system has a working CSPRNG. No code changes needed.\n\n**4. Error Message Simplification**\n- **Change**: Security-sensitive error messages are less verbose to prevent information leakage\n- **Impact**: Debugging authentication failures may require checking logs\n- **Migration**: Use server logs for detailed debugging; client errors are intentionally generic\n\n### No Migration Needed For\n\n- **Token cache expiry fix** - Fully backwards compatible\n- **State replay protection** - Legacy states without timestamp/nonce still accepted\n- **Input validation** - Only affects malformed requests\n- **go-sdk adapter fixes** - Fully backwards compatible\n\n---\n\n## Quick Start\n\n### Using mark3labs/mcp-go\n\n#### 1. Install\n\n```bash\ngo get github.com/tuannvm/oauth-mcp-proxy\n```\n\n#### 2. Add to Your Server\n\n```go\nimport (\n    oauth \"github.com/tuannvm/oauth-mcp-proxy\"\n    \"github.com/tuannvm/oauth-mcp-proxy/mark3labs\"\n)\n\nmux := http.NewServeMux()\n\n// Enable OAuth (one time setup)\noauthServer, oauthOption, _ := mark3labs.WithOAuth(mux, \u0026oauth.Config{\n    Provider: \"okta\",                    // or \"hmac\", \"google\", \"azure\"\n    Issuer:   \"https://your-company.okta.com\",\n    Audience: \"api://your-mcp-server\",\n    ServerURL: \"https://your-server.com\",\n})\n\n// Create MCP server with OAuth\nmcpServer := mcpserver.NewMCPServer(\"Server\", \"1.0.0\", oauthOption)\n\n// Add tools - all automatically protected\nmcpServer.AddTool(myTool, myHandler)\n\n// Setup endpoint with automatic 401 handling\nstreamable := mcpserver.NewStreamableHTTPServer(\n    mcpServer,\n    mcpserver.WithHTTPContextFunc(oauth.CreateHTTPContextFunc()),\n)\nmux.HandleFunc(\"/mcp\", oauthServer.WrapMCPEndpoint(streamable))\n```\n\n#### 3. Access Authenticated User\n\n```go\nfunc myHandler(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {\n    user, ok := oauth.GetUserFromContext(ctx)\n    if !ok {\n        return nil, fmt.Errorf(\"authentication required\")\n    }\n    // Use user.Username, user.Email, user.Subject\n}\n```\n\n---\n\n### Using Official SDK\n\n#### 1. Install\n\n```bash\ngo get github.com/modelcontextprotocol/go-sdk\ngo get github.com/tuannvm/oauth-mcp-proxy\n```\n\n#### 2. Add to Your Server\n\n```go\nimport (\n    \"github.com/modelcontextprotocol/go-sdk/mcp\"\n    oauth \"github.com/tuannvm/oauth-mcp-proxy\"\n    mcpoauth \"github.com/tuannvm/oauth-mcp-proxy/mcp\"\n)\n\nmux := http.NewServeMux()\n\n// Create MCP server\nmcpServer := mcp.NewServer(\u0026mcp.Implementation{\n    Name:    \"my-server\",\n    Version: \"1.0.0\",\n}, nil)\n\n// Add tools\nmcp.AddTool(mcpServer, \u0026mcp.Tool{\n    Name: \"greet\",\n    Description: \"Greet user\",\n}, func(ctx context.Context, req *mcp.CallToolRequest, params *struct{}) (*mcp.CallToolResult, any, error) {\n    user, _ := oauth.GetUserFromContext(ctx)\n    return \u0026mcp.CallToolResult{\n        Content: []mcp.Content{\n            \u0026mcp.TextContent{Text: \"Hello, \" + user.Username},\n        },\n    }, nil, nil\n})\n\n// Add OAuth protection\n_, handler, _ := mcpoauth.WithOAuth(mux, \u0026oauth.Config{\n    Provider: \"okta\",\n    Issuer:   \"https://your-company.okta.com\",\n    Audience: \"api://your-mcp-server\",\n}, mcpServer)\n\nhttp.ListenAndServe(\":8080\", handler)\n```\n\nYour MCP server now requires OAuth authentication.\n\n---\n\n## Examples\n\nSee [examples/README.md](examples/README.md) for detailed setup guide including Okta configuration.\n\n| SDK | Example | Description |\n|-----|---------|-------------|\n| **mark3labs** | [Simple](examples/mark3labs/simple/) | Minimal setup - copy/paste ready |\n| **mark3labs** | [Advanced](examples/mark3labs/advanced/) | ConfigBuilder, multiple tools, logging |\n| **Official** | [Simple](examples/official/simple/) | Minimal setup - copy/paste ready |\n| **Official** | [Advanced](examples/official/advanced/) | ConfigBuilder, multiple tools, logging |\n\n---\n\n## Supported Providers\n\n| Provider | Best For | Setup Guide |\n|----------|----------|-------------|\n| **HMAC** | Testing, development | [docs/providers/HMAC.md](docs/providers/HMAC.md) |\n| **Okta** | Enterprise SSO | [docs/providers/OKTA.md](docs/providers/OKTA.md) |\n| **Google** | Google Workspace | [docs/providers/GOOGLE.md](docs/providers/GOOGLE.md) |\n| **Azure AD** | Microsoft 365 | [docs/providers/AZURE.md](docs/providers/AZURE.md) |\n\n---\n\n## Documentation\n\n**Getting Started:**\n\n- [Setup Guide](docs/CLIENT-SETUP.md) - Complete server integration and client configuration\n- [Configuration Guide](docs/CONFIGURATION.md) - All config options\n- [Provider Setup](docs/providers/) - OAuth provider guides\n\n**Advanced:**\n\n- [Security Guide](docs/SECURITY.md) - Production best practices\n- [Troubleshooting](docs/TROUBLESHOOTING.md) - Common issues\n\n---\n\n## License\n\nMIT License - See [LICENSE](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftuannvm%2Foauth-mcp-proxy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftuannvm%2Foauth-mcp-proxy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftuannvm%2Foauth-mcp-proxy/lists"}