Configuration Guide
Complete reference for oauth-mcp-proxy configuration options.
Config Struct
type Config struct {
// Required
Provider string // "hmac", "okta", "google", "azure"
Audience string // Your API audience
// Provider-specific
Issuer string // OIDC issuer URL (Okta/Google/Azure)
JWTSecret []byte // Secret key (HMAC only)
// Optional - OAuth Mode
Mode string // "native" or "proxy" - auto-detected
// Optional - Proxy Mode
ClientID string // OAuth client ID
ClientSecret string // OAuth client secret
ServerURL string // Your server's public URL
RedirectURIs string // Allowed redirect URIs
// Optional - Logging
Logger Logger // Custom logger implementation
}
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:
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",
})
Google
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
Last updated
Was this helpful?