How OpenSEO Manages OAuth Tokens and Garbage Collection for the MCP Server

OpenSEO implements OAuth 2.0 for its Multi-Client Protocol (MCP) server using Cloudflare KV storage with configurable TTLs and a dedicated cron-based garbage collection routine that purges orphaned grant records in batches of 200 to prevent storage accumulation.

The OpenSEO repository leverages the @cloudflare/workers-oauth-provider library to secure MCP server endpoints. This implementation, centralized in src/server/mcp/oauth-provider.ts, defines strict token lifecycles, persistent grant storage, and automated cleanup mechanisms that ensure expired credentials do not clutter the KV namespace while maintaining secure authentication flows.

OAuth Token Lifecycle Configuration

OpenSEO defines three distinct TTL values to balance security and user convenience. These constants are declared at the top of the provider configuration file to govern how long authentication artifacts remain valid.

Access and Refresh Token TTLs

Access tokens expire after 24 hours, configured at line 49 of src/server/mcp/oauth-provider.ts. Refresh tokens persist for 30 days, defined at line 50. This tiered approach allows clients to maintain long-lived sessions while ensuring that active API access requires frequently refreshed credentials.

Client Registration Persistence

When a client registers via the /api/auth/oauth2/register endpoint (lines 53‑55), the provider creates a registration record with a 365‑day TTL. This extended lifetime prevents intermittent "invalid_client" errors for legitimate applications while ensuring that abandoned client registrations eventually expire automatically.

Grant Properties and KV Storage

Token metadata and user context are persisted in the OAUTH_KV namespace (declared at line 58) using structured grant properties. The createWorkersOAuthMcpProps helper, imported at line 21, constructs this metadata object at lines 36‑44, capturing:

  • userId and email for identity resolution
  • organizationId for multi-tenant access control
  • baseUrl and clientId for routing validation
  • Granted scopes for permission enforcement

These properties are bound to the OAuth grant and retrieved during token validation to authorize subsequent MCP requests.

Handling OAuth Requests

The provider exposes distinct handlers for each phase of the OAuth flow, with explicit CSRF protection and an API-key fallback for non-OAuth scenarios.

handleOAuthAuthorizeRequest (lines 51‑70) validates incoming authorization requests, verifies user authentication status, and redirects to the consent page. Upon user approval, handleOAuthConsentResponse (lines 72‑71) validates the POST payload, checks CSRF protection (csrfProtected at lines 58‑60), and invokes oauth.completeAuthorization (lines 45‑55) to issue the access and refresh tokens.

API Key Fallback

For legacy or automated integrations, handleMcpApiKeyRequest (referenced at line 50) intercepts requests before the OAuth flow initiates, allowing authentication via static API keys when OAuth tokens are not present.

Garbage Collection Strategy

While Cloudflare KV automatically expires keys based on their TTLs, orphaned grant records—entries referencing expired client registrations—are not automatically purged. OpenSEO implements an explicit cleanup routine to reclaim this space.

The purgeExpiredData method (lines 64‑71) runs on a scheduled Worker cron job:

// src/server/mcp/oauth-provider.ts
purgeExpiredData(env: OpenSeoOAuthEnv) {
  return getProvider().purgeExpiredData(env, { batchSize: 200 });
}

This sweep iterates over the KV namespace in batches of 200 keys, deleting stale tokens, expired refresh tokens, and grant entries no longer associated with active client registrations. This prevents indefinite accumulation of dead records while operating within Cloudflare's rate limits.

Provider Configuration and Validation

The createProvider function (lines 99‑35) wires together the OAuth implementation with specific callbacks for security enforcement. The tokenExchangeCallback (lines 16‑31) validates that every token exchange request includes the mandatory MCP_SCOPE and rebuilds grant properties for the newly issued token. Error handling is centralized via onError: logOAuthError (line 32), categorizing 401 responses as debug logs, 5xx as errors, and other issues as warnings.

Summary

  • Token lifetimes are strictly tiered: 24 hours for access tokens, 30 days for refresh tokens, and 365 days for client registrations.
  • Grant data is stored in the OAUTH_KV namespace with structured properties created by createWorkersOAuthMcpProps.
  • Garbage collection runs via cron-triggered purgeExpiredData calls that remove orphaned KV entries in 200-record batches.
  • Security validation includes mandatory MCP_SCOPE checks during token exchange and CSRF protection on consent endpoints.

Frequently Asked Questions

What are the exact TTL values for OpenSEO OAuth tokens?

Access tokens expire after 24 hours, refresh tokens after 30 days, and client registrations persist for 365 days according to the configuration in src/server/mcp/oauth-provider.ts at lines 49, 50, and 55 respectively.

How does the garbage collection system handle orphaned data?

The purgeExpiredData method iterates through the OAUTH_KV namespace in batches of 200 keys to explicitly delete grant records associated with expired client registrations, since standard KV TTLs do not automatically cascade deletes to related metadata entries.

What validation occurs during token refresh?

The tokenExchangeCallback validates that every refresh request includes the mandatory MCP_SCOPE and reconstructs the grant properties object to ensure the new token carries correct user, organization, and permission context.

Where is OAuth data stored in the OpenSEO architecture?

All token metadata and grant properties are stored in the Cloudflare KV namespace OAUTH_KV, defined at line 58 of src/server/mcp/oauth-provider.ts, while client registrations and tokens are managed by the workers-oauth-provider library with TTL-based expiration.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →