Configuration Guide
April 3, 2026 · View on GitHub
Complete reference for oauth-mcp-proxy configuration options.
Config Struct
type Config struct {
// Required
Provider string // "hmac", "okta", "google", "azure"
// Provider-specific
Issuer string // OIDC issuer URL (Okta/Google/Azure) - validated for HTTPS
JWTSecret []byte // Secret key (HMAC only)
Audience string // Your API audience
// Optional - OAuth Mode
Mode string // "native" or "proxy" - auto-detected from ClientID presence
// Optional - Proxy Mode (server-side OAuth flow)
ClientID string // OAuth client ID (triggers proxy mode)
ClientSecret string // OAuth client secret
ServerURL string // Your server's public URL
RedirectURIs string // Allowed redirect URIs (comma-separated allowlist)
// Optional - Fixed Redirect Mode (for mcp-remote)
FixedRedirectURI string // Single fixed redirect URI for proxying callbacks
AllowedClientRedirectDomains string // Comma-separated domain suffixes allowed for client redirects
// Optional - Token Validation
Scopes []string // OAuth scopes
SkipAudienceCheck bool // Skip audience validation (not recommended)
// Optional - Logging
Logger Logger // Custom logger implementation
}
Key Configuration Notes
Issuer URL Validation (OIDC providers):
- Must use HTTPS for non-localhost URLs (enforced for security)
- Must be a valid URL format
- Cannot be empty
- Prevents MITM attacks on OAuth communication
⚠️ Breaking Changes (v1.1.0):
-
Issuer URL Validation: OIDC providers now enforce HTTPS. Non-HTTPS issuer URLs will cause configuration validation to fail.
// ✅ Valid Issuer: "https://company.okta.com" Issuer: "http://localhost:8080" // Testing only // ❌ Invalid - will fail validation Issuer: "http://company.okta.com" // Must use HTTPS -
State Signing Key:
NewServer()now panics if state signing key cannot be generated (crypto/rand failure). This ensures security but means server startup will fail on systems with broken CSPRNG. -
Nonce Generation:
generateSecureNonce()now panics instead of falling back to weak timestamp-based nonces.
See SECURITY.md for detailed migration guide.
Redirect URI Configuration (Proxy Mode):
- Option 1:
RedirectURIs- Comma-separated allowlist of exact URIs - Option 2:
FixedRedirectURI- Single fixed URI for proxying callbacks - Additional:
AllowedClientRedirectDomains- Domain suffixes allowed for client redirects (in addition to localhost)
Mode Detection:
Mode = "native"- Token validation only (ClientID not set)Mode = "proxy"- Full OAuth flow (ClientID is set)- Auto-detected from
ClientIDpresence if not specified
Configuration Methods
Direct Config
Create Config struct directly:
cfg := &oauth.Config{
Provider: "okta",
Issuer: "https://company.okta.com",
Audience: "api://my-server",
ServerURL: "https://my-server.com",
}
_, oauthOption, _ := oauth.WithOAuth(mux, cfg)
ConfigBuilder (v0.2.0+)
Use fluent API with auto-generated ServerURL:
cfg, _ := oauth.NewConfigBuilder().
WithProvider("okta").
WithIssuer("https://company.okta.com").
WithAudience("api://my-server").
WithHost("my-server.com").
WithPort("443").
WithTLS(true). // Auto-generates https://my-server.com:443
Build()
Benefits:
- Auto-generates ServerURL from host/port/TLS
- Validates config during Build()
- Cleaner, more readable code
FromEnv() (v0.2.0+)
Read configuration from environment variables:
cfg, _ := oauth.FromEnv()
_, oauthOption, _ := oauth.WithOAuth(mux, cfg)
Environment variables:
OAUTH_PROVIDER- Provider nameOAUTH_MODE- OAuth mode (optional)OIDC_ISSUER- Issuer URLOIDC_AUDIENCE- AudienceOIDC_CLIENT_ID- Client ID (proxy mode)OIDC_CLIENT_SECRET- Client secret (proxy mode)OAUTH_REDIRECT_URIS- Redirect URIs (proxy mode)JWT_SECRET- HMAC secretMCP_URL- Full server URL (or auto-generated from below)MCP_HOST- Server host (default: localhost)MCP_PORT- Server port (default: 8080)HTTPS_CERT_FILE- TLS cert file (enables HTTPS)HTTPS_KEY_FILE- TLS key file (enables HTTPS)
Benefits:
- 12-factor app compliant
- Easy Kubernetes/Docker deployment
- No code changes for config updates
Required Fields
Provider
Type: string
Required: Yes
Values: "hmac", "okta", "google", "azure"
Specifies which OAuth provider to use for token validation.
Provider: "okta" // Use Okta OIDC validation
See: Provider Guides for setup instructions
Audience
Type: string
Required: Yes
Purpose: Validates the aud claim in JWT tokens
The audience must match exactly. This prevents token reuse across services.
Examples:
// Custom audience
Audience: "api://my-mcp-server"
// Google (use Client ID)
Audience: "123456789.apps.googleusercontent.com"
// Azure (use Application ID or App ID URI)
Audience: "api://my-server"
// or
Audience: "12345678-1234-1234-1234-123456789012"
Provider-Specific Fields
Issuer
Type: string
Required: For OIDC providers (okta, google, azure)
Not used: HMAC provider
The OAuth provider's issuer URL. Must match token's iss claim exactly.
Examples:
// Okta
Issuer: "https://yourcompany.okta.com"
// Google
Issuer: "https://accounts.google.com"
// Azure AD (single tenant)
Issuer: "https://login.microsoftonline.com/{tenant-id}/v2.0"
// Azure AD (multi-tenant)
Issuer: "https://login.microsoftonline.com/common/v2.0"
Important:
- No trailing slash
- Must serve
/.well-known/openid-configuration - HTTPS required
JWTSecret
Type: []byte
Required: For HMAC provider only
Not used: OIDC providers
Shared secret for HMAC-SHA256 token validation.
Examples:
// From environment (recommended)
JWTSecret: []byte(os.Getenv("JWT_SECRET"))
// Minimum 32 bytes recommended
JWTSecret: []byte("your-very-long-secret-key-min-32-bytes")
// Generate securely
secret := make([]byte, 32)
rand.Read(secret)
JWTSecret: secret
Security: Never hardcode! Use environment variables. See SECURITY.md.
OAuth Mode
Mode
Type: string
Optional: Auto-detected if not specified
Values: "native", "proxy"
Determines whether client or server handles OAuth flow.
Auto-detection:
// If ClientID is provided → proxy mode
// If ClientID is empty → native mode
Mode: "" // Let library auto-detect
Explicit:
Mode: "native" // Client does OAuth
Mode: "proxy" // Server proxies OAuth
Native Mode
When: OAuth-capable clients (Claude Desktop, browser apps)
Client: Authenticates directly with provider → Gets token → Calls MCP server Server: Only validates tokens (no OAuth endpoints used)
Config:
oauth.WithOAuth(mux, &oauth.Config{
Mode: "native", // Or omit (auto-detected)
Provider: "okta",
Issuer: "https://company.okta.com",
Audience: "api://my-server",
// No ClientID/ServerURL/RedirectURIs needed
})
OAuth endpoints: Return 404 with helpful message (not needed by client)
Proxy Mode
When: Simple clients that can't do OAuth (CLI tools, legacy clients)
Client: Calls MCP server → Server proxies to provider → Returns token to client Server: Full OAuth authorization server functionality
Config:
oauth.WithOAuth(mux, &oauth.Config{
Mode: "proxy", // Or omit (auto-detected from ClientID)
Provider: "okta",
Issuer: "https://company.okta.com",
Audience: "api://my-server",
ClientID: "your-client-id", // Required for proxy mode
ClientSecret: "your-client-secret", // Required for proxy mode
ServerURL: "https://your-server.com", // Required for proxy mode
RedirectURIs: "https://your-server.com/oauth/callback", // Required
})
OAuth endpoints: Fully functional (/oauth/authorize, /oauth/callback, /oauth/token)
Mode Comparison:
| Native | Proxy | |
|---|---|---|
| Client capability | Can do OAuth | Cannot do OAuth |
| OAuth flow | Client ↔ Provider | Client ↔ Server ↔ Provider |
| Config required | Minimal | Full (ClientID, ServerURL, etc.) |
| Endpoints active | Metadata only | All endpoints |
| Use case | Production apps | Simple clients |
Proxy Mode Fields
ClientID
Type: string
Required: For proxy mode
Purpose: OAuth client identifier from provider
Obtained from your OAuth provider:
- Okta: Application → General → Client ID
- Google: Cloud Console → Credentials → OAuth 2.0 Client ID
- Azure: App registrations → Application (client) ID
ClientID: "0oa..." // Okta
ClientID: "123.apps.googleusercontent.com" // Google
ClientID: "12345678-1234-1234-1234-123456789012" // Azure
ClientSecret
Type: string
Required: For proxy mode (confidential clients)
Purpose: OAuth client secret for token exchange
Security:
// ✅ From environment
ClientSecret: os.Getenv("OAUTH_CLIENT_SECRET")
// ❌ Never hardcode
ClientSecret: "abc123..." // SECURITY VIOLATION
See: SECURITY.md for secret management best practices.
ServerURL
Type: string
Required: For proxy mode
Purpose: Your MCP server's public URL
Used for:
- OAuth metadata endpoints (issuer URL)
- Redirect URI construction
- Endpoint URL generation
ServerURL: "https://mcp-server.example.com" // Production
ServerURL: "https://mcp-server.herokuapp.com" // Cloud deployment
ServerURL: "http://localhost:8080" // Local testing
Requirements:
- HTTPS in production
- No trailing slash
- Publicly accessible (for OAuth provider callbacks)
RedirectURIs
Type: string
Required: For proxy mode
Purpose: OAuth redirect URI validation
Single URI (Fixed Redirect):
RedirectURIs: "https://your-server.com/oauth/callback"
Server uses this URI with provider. For security, client redirects must be localhost only.
Multiple URIs (Allowlist):
RedirectURIs: "https://app1.com/callback,https://app2.com/callback,https://app3.com/callback"
Comma-separated list. Client's redirect_uri must exactly match one of these.
Security:
- HTTPS required for non-localhost
- No wildcards allowed
- Exact string match
- See SECURITY.md for redirect URI security
Optional Fields
Logger
Type: Logger interface
Default: Uses log.Printf with level prefixes
Purpose: Custom logging integration
Implement Logger interface to integrate with your logging system:
type Logger interface {
Debug(msg string, args ...interface{})
Info(msg string, args ...interface{})
Warn(msg string, args ...interface{})
Error(msg string, args ...interface{})
}
Examples:
Zap:
type ZapLogger struct{ logger *zap.Logger }
func (l *ZapLogger) Info(msg string, args ...interface{}) {
l.logger.Sugar().Infof(msg, args...)
}
// ... implement Debug, Warn, Error
cfg := &oauth.Config{
Provider: "okta",
Logger: &ZapLogger{logger: zapLogger},
}
Logrus:
type LogrusLogger struct{ logger *logrus.Logger }
func (l *LogrusLogger) Info(msg string, args ...interface{}) {
l.logger.Infof(msg, args...)
}
// ... implement Debug, Warn, Error
cfg := &oauth.Config{
Logger: &LogrusLogger{logger: logrusLogger},
}
Default behavior:
[INFO] OAuth2: Authorization request - client_id: ...
[WARN] SECURITY: Invalid redirect URI ...
[ERROR] OAuth2: Token validation failed: ...
What gets logged: See examples/README.md
Validation
Configuration is validated when calling WithOAuth() or NewServer():
_, oauthOption, err := oauth.WithOAuth(mux, cfg)
if err != nil {
// err describes what's wrong:
// - "provider is required"
// - "JWTSecret is required for HMAC provider"
// - "proxy mode requires ClientID"
// - etc.
log.Fatal(err)
}
Validation Rules
All modes:
- Provider must be one of: hmac, okta, google, azure
- Audience is required
- Provider-specific fields validated (JWTSecret for HMAC, Issuer for OIDC)
Proxy mode:
- ClientID required
- ServerURL required
- RedirectURIs required
Native mode:
- ClientID, ServerURL, RedirectURIs optional (ignored if provided)
Complete Examples
HMAC (Testing)
oauth.WithOAuth(mux, &oauth.Config{
Provider: "hmac",
Audience: "api://my-server",
JWTSecret: []byte(os.Getenv("JWT_SECRET")),
})
Okta (Native - Recommended)
oauth.WithOAuth(mux, &oauth.Config{
Provider: "okta",
Issuer: os.Getenv("OKTA_ISSUER"),
Audience: "api://my-server",
})
Okta (Proxy - For Simple Clients)
oauth.WithOAuth(mux, &oauth.Config{
Provider: "okta",
Issuer: os.Getenv("OKTA_ISSUER"),
Audience: "api://my-server",
ClientID: os.Getenv("OKTA_CLIENT_ID"),
ClientSecret: os.Getenv("OKTA_CLIENT_SECRET"),
ServerURL: "https://mcp.example.com",
RedirectURIs: "https://mcp.example.com/oauth/callback",
})
oauth.WithOAuth(mux, &oauth.Config{
Provider: "google",
Issuer: "https://accounts.google.com",
Audience: os.Getenv("GOOGLE_CLIENT_ID"), // Use Client ID as audience
})
Azure AD
oauth.WithOAuth(mux, &oauth.Config{
Provider: "azure",
Issuer: fmt.Sprintf("https://login.microsoftonline.com/%s/v2.0",
os.Getenv("AZURE_TENANT_ID")),
Audience: os.Getenv("AZURE_CLIENT_ID"),
})
Environment Variables Pattern
Recommended .env structure:
# OAuth Provider
OAUTH_PROVIDER=okta
OAUTH_ISSUER=https://yourcompany.okta.com
OAUTH_AUDIENCE=api://my-mcp-server
# HMAC (if using)
JWT_SECRET=your-32-byte-secret-key
# Proxy Mode (if using)
OAUTH_CLIENT_ID=your-client-id
OAUTH_CLIENT_SECRET=your-client-secret
OAUTH_SERVER_URL=https://your-server.com
OAUTH_REDIRECT_URIS=https://your-server.com/oauth/callback
Load in code:
import "github.com/joho/godotenv"
func main() {
godotenv.Load()
oauth.WithOAuth(mux, &oauth.Config{
Provider: os.Getenv("OAUTH_PROVIDER"),
Issuer: os.Getenv("OAUTH_ISSUER"),
Audience: os.Getenv("OAUTH_AUDIENCE"),
ClientID: os.Getenv("OAUTH_CLIENT_ID"),
ClientSecret: os.Getenv("OAUTH_CLIENT_SECRET"),
ServerURL: os.Getenv("OAUTH_SERVER_URL"),
RedirectURIs: os.Getenv("OAUTH_REDIRECT_URIS"),
JWTSecret: []byte(os.Getenv("JWT_SECRET")),
})
}
See Also
- Provider Guides - Provider-specific setup
- SECURITY.md - Security best practices
- TROUBLESHOOTING.md - Common configuration issues