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

> Learn how OpenSEO manages OAuth tokens and garbage collection for the MCP server. Discover its use of Cloudflare KV, TTLs, and batch purging for efficient storage.

- Repository: [Every App/open-seo](https://github.com/every-app/open-seo)
- Tags: internals
- Published: 2026-09-02

---

**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`](https://github.com/every-app/open-seo/blob/main/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`](https://github.com/every-app/open-seo/blob/main/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.

### Authorization and Consent

`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:

```typescript
// 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`](https://github.com/every-app/open-seo/blob/main/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`](https://github.com/every-app/open-seo/blob/main/src/server/mcp/oauth-provider.ts), while client registrations and tokens are managed by the `workers-oauth-provider` library with TTL-based expiration.