# How Cloudflare Access Gates the `/mcp` Route and Which Headers `resolveUserContextFromHeaders` Uses

> Learn how Cloudflare Access secures the mcp route using CF Access headers like email and ID. Understand resolveUserContextFromHeaders in the every-app/open-seo repo.

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

---

**`resolveUserContextFromHeaders` secures the `/mcp` endpoint by validating Cloudflare Access headers—specifically `CF-Access-Authenticated-User-Email`, `CF-Access-Authenticated-User-Name`, `CF-Access-Authenticated-User-Id`, and `CF-Access-Client-Id`—to build a trusted user context in the `every-app/open-seo` repository.**

The `every-app/open-seo` repository implements Zero Trust security for its Managed Control Panel (MCP) by gating the `/mcp` route through Cloudflare Access. When a request arrives, the server invokes `resolveUserContextFromHeaders` (located in [`src/middleware/ensure-user/resolve.ts`](https://github.com/every-app/open-seo/blob/main/src/middleware/ensure-user/resolve.ts)) to extract identity metadata from Cloudflare-specific headers. This centralized approach ensures that only authenticated users with valid Cloudflare Access tokens can interact with MCP resources.

## Gating the `/mcp` Route Through Middleware

### Transport Layer Integration

In [`src/server/mcp/transport.ts`](https://github.com/every-app/open-seo/blob/main/src/server/mcp/transport.ts) (around line 225), the MCP handler creation process begins by resolving the user context before executing any business logic. The transport layer imports the resolution helper and awaits the user context, effectively blocking unauthorized requests at the edge.

```typescript
// src/server/mcp/transport.ts
import { resolveUserContextFromHeaders } from "@/middleware/ensure-user/resolve";

async function handleRequest(request: Request) {
  const userContext = await resolveUserContextFromHeaders(request.headers);
  // Proceed only if userContext is valid
}

```

### Delegation to the Cloudflare Access Resolver

The `resolveUserContextFromHeaders` function acts as a thin wrapper that delegates to `resolveCloudflareAccessContext` inside [`src/middleware/ensure-user/cloudflareAccess.ts`](https://github.com/every-app/open-seo/blob/main/src/middleware/ensure-user/cloudflareAccess.ts) (export declaration around line 39). This module checks if the deployment runs in Cloudflare Access mode via `isCloudflareAccessMode()`, then parses the identity headers to construct a normalized **UserContext** object.

## Headers Consumed by `resolveUserContextFromHeaders`

The actual header extraction occurs in [`src/middleware/ensure-user/cloudflareAccess.ts`](https://github.com/every-app/open-seo/blob/main/src/middleware/ensure-user/cloudflareAccess.ts) between lines 50 and 80. The resolver specifically looks for Cloudflare Access identity headers prefixed with `CF-Access-`.

### Required Cloudflare Access Identity Headers

The function requires the following headers to build a complete user profile:

- `CF-Access-Authenticated-User-Email` – The verified email address of the authenticated user.
- `CF-Access-Authenticated-User-Name` – The display name associated with the Cloudflare Access identity.
- `CF-Access-Authenticated-User-Id` – A unique identifier generated by Cloudflare for the user.
- `CF-Access-Client-Id` – The client identifier associated with the Access application.

### Optional Authorization Header

In some configurations, the resolver also inspects the standard `Authorization` header for a Bearer token containing the Cloudflare Access JWT. This provides a fallback or additional validation layer when the CF-Access headers are not directly available.

## Practical Implementation Example

Below is a condensed example demonstrating how to manually invoke the resolver for testing or custom middleware purposes.

```typescript
// Example: Manually resolving user context from Cloudflare Access headers
import { resolveUserContextFromHeaders } from "@/middleware/ensure-user/resolve";

async function authenticateRequest(request: Request) {
  try {
    const context = await resolveUserContextFromHeaders(request.headers);
    console.log("Authenticated user:", context.email);
    return context;
  } catch (error) {
    throw new Error("Invalid Cloudflare Access headers");
  }
}

// Simulating headers from Cloudflare Access
const mockHeaders = new Headers({
  "CF-Access-Authenticated-User-Email": "user@example.com",
  "CF-Access-Authenticated-User-Name": "Example User",
  "CF-Access-Authenticated-User-Id": "user-12345",
  "CF-Access-Client-Id": "app-client-id-67890",
});

authenticateRequest(new Request("https://example.com/mcp", { headers: mockHeaders }));

```

## Key Source Files

| File | Purpose | Location |
|------|---------|----------|
| [`src/server/mcp/transport.ts`](https://github.com/every-app/open-seo/blob/main/src/server/mcp/transport.ts) | MCP transport entry point; invokes user context resolution before handling requests. | [`src/server/mcp/transport.ts`](https://github.com/every-app/open-seo/blob/main/src/server/mcp/transport.ts) |
| [`src/middleware/ensure-user/resolve.ts`](https://github.com/every-app/open-seo/blob/main/src/middleware/ensure-user/resolve.ts) | Entry point for `resolveUserContextFromHeaders`; delegates to Cloudflare-specific logic. | [`src/middleware/ensure-user/resolve.ts`](https://github.com/every-app/open-seo/blob/main/src/middleware/ensure-user/resolve.ts) |
| [`src/middleware/ensure-user/cloudflareAccess.ts`](https://github.com/every-app/open-seo/blob/main/src/middleware/ensure-user/cloudflareAccess.ts) | Core implementation of `resolveCloudflareAccessContext`; parses CF-Access headers around lines 50-80. | [`src/middleware/ensure-user/cloudflareAccess.ts`](https://github.com/every-app/open-seo/blob/main/src/middleware/ensure-user/cloudflareAccess.ts) |

The transport layer depends on the middleware layer to ensure that every request to `/mcp` carries valid Cloudflare Access credentials before any MCP method is executed.

## Summary

- The `/mcp` route is protected by Cloudflare Access middleware that intercepts every request in [`src/server/mcp/transport.ts`](https://github.com/every-app/open-seo/blob/main/src/server/mcp/transport.ts).
- `resolveUserContextFromHeaders` serves as the primary entry point for extracting identity data, delegating to `resolveCloudflareAccessContext`.
- The resolver consumes four specific Cloudflare Access headers: `CF-Access-Authenticated-User-Email`, `CF-Access-Authenticated-User-Name`, `CF-Access-Authenticated-User-Id`, and `CF-Access-Client-Id`.
- An optional `Authorization` header may also be evaluated for Bearer token validation.
- This architecture centralizes authentication logic, ensuring consistent user context across the MCP server.

## Frequently Asked Questions

### What is the role of `resolveUserContextFromHeaders` in the Open SEO codebase?

`resolveUserContextFromHeaders` is the main interface for extracting authenticated user details from incoming request headers. Located in [`src/middleware/ensure-user/resolve.ts`](https://github.com/every-app/open-seo/blob/main/src/middleware/ensure-user/resolve.ts), it forwards header processing to `resolveCloudflareAccessContext`, which specifically handles Cloudflare Access identity headers. This design keeps the transport layer agnostic of the specific identity provider while enforcing strict authentication at the edge.

### Which specific headers does the resolver check to identify a user?

The resolver checks for `CF-Access-Authenticated-User-Email`, `CF-Access-Authenticated-User-Name`, `CF-Access-Authenticated-User-Id`, and `CF-Access-Client-Id`. These headers are injected by Cloudflare Access after successful authentication. The resolver may also inspect the `Authorization` header for a JWT Bearer token in certain deployment scenarios.

### How does the MCP transport layer enforce Cloudflare Access authentication?

In [`src/server/mcp/transport.ts`](https://github.com/every-app/open-seo/blob/main/src/server/mcp/transport.ts) (approximately line 225), the MCP handler awaits `resolveUserContextFromHeaders` before executing any MCP logic. If the resolver fails to validate the headers or the headers are missing, the request is rejected before reaching the business logic layer, effectively gating the entire `/mcp` route.

### Can `resolveUserContextFromHeaders` be used outside of the MCP transport?

Yes. While primarily used to secure the `/mcp` endpoint, the function is exported from the middleware module and can be imported into any route handler or worker script within the repository. This allows other sensitive endpoints to leverage the same Cloudflare Access validation logic without duplicating code.