v2.18.0 - OAuth 2.1 Implementation with Token Refresh
v2.18.0 - OAuth 2.1 Implementation with Token Refresh 🔐
This release implements full OAuth 2.1 compliance for MCP server authentication, including automatic token refresh, RFC 9728 discovery, and dynamic client registration.
🎯 Major Features
OAuth 2.1 Full Implementation
- OAuth 2.1 Specification Compliance: Complete implementation of OAuth 2.1 standards
- Automatic Token Refresh: Tokens are automatically refreshed before expiration
- Token Rotation: OAuth 2.1 refresh token rotation for enhanced security
- PKCE (Proof Key for Code Exchange): SHA-256 code challenge support for secure flows
- State Parameter Binding: HMAC integrity hash to prevent tampering
- Short-lived States: 5-minute state expiration (OAuth 2.1 requirement)
RFC 9728 OAuth Server Metadata Discovery
- Automatic discovery of OAuth endpoints from MCP servers
- Supports
WWW-Authenticateheader-based discovery - Falls back to
.well-known/oauth-authorization-serverdiscovery - Stores discovered configuration for future use
- Files:
lib/oauth/rfc9728-discovery.ts
RFC 7591 Dynamic Client Registration
- Automatic client registration with OAuth providers
- Reuses existing client credentials when available
- Supports confidential and public client types
- Stores client credentials securely (encrypted)
- Files:
lib/oauth/dynamic-client-registration.ts
Token Management
- Encrypted Token Storage: All tokens encrypted at rest (AES-256-GCM)
- Token Expiration Tracking: Automatic detection of expired tokens
- Refresh Token Support: Long-lived refresh tokens for continuous access
- Scope Management: Tracks and validates OAuth scopes
- Database Tables:
mcp_server_oauth_tokens- Encrypted token storagemcp_server_oauth_config- OAuth configuration per serveroauth_pkce_states- PKCE state management (5-minute TTL)
🔐 Security Enhancements
SSRF Protection
- Comprehensive validation of all OAuth URLs
- Blocks private IP ranges and localhost
- Prevents access to cloud metadata endpoints
- Rate-limited endpoint probing (max 2 attempts)
- Files:
lib/oauth/ssrf-protection.ts
Race Condition Protection
- Optimistic locking for token updates with version field
- Prevents concurrent token refresh conflicts
- Detects and reports race conditions
- Migration:
drizzle/0074_gifted_fallen_one.sql
Error Sanitization
- Production-safe error messages
- Prevents information disclosure
- Development mode preserves debugging details
- Files:
lib/oauth/error-sanitization.ts
Reduced Attack Surface
- Timeouts reduced to 3-5 seconds
- HTTP Basic Auth for confidential clients (RFC 6749)
- User-scoped PKCE states (prevents OAuth hijacking)
- Integrity hash binding for state parameters
📊 Database Schema Changes
New Tables
-- OAuth tokens (encrypted storage)
CREATE TABLE mcp_server_oauth_tokens (
uuid UUID PRIMARY KEY,
server_uuid UUID REFERENCES mcp_servers(uuid),
access_token_encrypted TEXT NOT NULL,
refresh_token_encrypted TEXT,
token_type TEXT DEFAULT 'Bearer',
expires_at TIMESTAMP,
scopes TEXT[],
version INTEGER DEFAULT 1, -- NEW: Optimistic locking
created_at TIMESTAMP,
updated_at TIMESTAMP
);
-- OAuth configuration (per server)
CREATE TABLE mcp_server_oauth_config (
uuid UUID PRIMARY KEY,
server_uuid UUID REFERENCES mcp_servers(uuid),
authorization_endpoint TEXT NOT NULL,
token_endpoint TEXT NOT NULL,
registration_endpoint TEXT,
client_id TEXT,
client_secret_encrypted TEXT,
scopes TEXT[],
supports_pkce BOOLEAN DEFAULT true,
discovery_method TEXT
);
-- PKCE states (5-minute TTL)
CREATE TABLE oauth_pkce_states (
state TEXT PRIMARY KEY,
server_uuid UUID REFERENCES mcp_servers(uuid),
user_id TEXT NOT NULL, -- Binds to user
code_verifier TEXT NOT NULL,
redirect_uri TEXT NOT NULL,
integrity_hash TEXT NOT NULL, -- HMAC binding
expires_at TIMESTAMP NOT NULL
);Migration Required
pnpm db:migrate🔄 OAuth Flow
For STREAMABLE_HTTP/SSE Servers:
- Discovery: RFC 9728 metadata discovery from server
- Registration: Dynamic client registration (if supported)
- Authorization: User redirected to authorization endpoint
- PKCE: SHA-256 code challenge generated and verified
- Token Exchange: Authorization code exchanged for tokens
- Storage: Tokens encrypted and stored in database
- Refresh: Automatic token refresh before expiration
Supported Discovery Methods:
rfc9728- RFC 9728 OAuth Server Metadatawww-authenticate- WWW-Authenticate header parsingmanual- Manual configuration
📁 New Files
OAuth Core:
lib/oauth/rfc9728-discovery.ts- RFC 9728 metadata discoverylib/oauth/dynamic-client-registration.ts- RFC 7591 registrationlib/oauth/oauth-config-store.ts- Configuration management (5-min cache)lib/oauth/integrity.ts- HMAC integrity hash generationlib/oauth/pkce-cleanup.ts- Expired state cleanup
Security:
lib/oauth/ssrf-protection.ts- SSRF validationlib/oauth/error-sanitization.ts- Error sanitization
API Routes:
app/api/oauth/callback/route.ts- OAuth callback handler
Database:
drizzle/0074_gifted_fallen_one.sql- Version field migration
🎯 Server Type Support
| Server Type | OAuth 2.1 | Token Refresh | PKCE | Discovery |
|---|---|---|---|---|
| STREAMABLE_HTTP | ✅ | ✅ | ✅ | ✅ RFC 9728 |
| SSE | ✅ | ✅ | ✅ | ✅ RFC 9728 |
| mcp-remote | ✅ | ❌ | ||
| STDIO | ❌ | ❌ | ❌ | ❌ |
🔄 Upgrade Instructions
-
Pull latest changes:
git pull origin main
-
Install dependencies:
pnpm install
-
Apply database migration:
pnpm db:migrate
-
Restart application:
pnpm build pnpm start
-
Configure OAuth (optional):
OAUTH_CLIENT_ID=your-client-id # Fallback if registration fails NEXTAUTH_URL=https://your-domain.com # Required for redirects
🔍 Testing OAuth Flow
- Add an MCP server that requires OAuth (e.g., Linear, GitHub)
- Click "Authenticate" button when server returns 401
- Complete OAuth flow in browser
- Tokens are automatically refreshed
- Check logs for
[OAuth]entries
📊 Monitoring
Monitor these log patterns:
[OAuth] RFC 9728 discovery successful[OAuth] PKCE enabled for OAuth flow[OAuth] Using HTTP Basic Authentication[OAuth SSRF]- Blocked SSRF attemptsToken was updated by another request- Race condition detected
⚠️ Breaking Changes
None. All changes are backward compatible. Existing mcp-remote OAuth flows continue to work.
🙏 Credits
OAuth 2.1 implementation follows:
- RFC 6749: OAuth 2.0 Authorization Framework
- RFC 7636: Proof Key for Code Exchange (PKCE)
- RFC 7591: OAuth 2.0 Dynamic Client Registration
- RFC 8707: Resource Indicators for OAuth 2.0
- RFC 9728: OAuth 2.0 Authorization Server Metadata
- OAuth 2.1 Draft: Latest security best practices
Full Changelog: v2.17.0...v2.18.0