# How OpenSEO Handles Authentication: Cloudflare Access, OAuth, and API Key Architecture

> Discover how OpenSEO secures your data with Cloudflare Access JWT verification, OAuth, and API key authentication. Learn about its robust multi-layered security architecture.

- Repository: [Every App/open-seo](https://github.com/every-app/open-seo)
- Tags: architecture
- Published: 2026-08-30

---

**OpenSEO implements a multi-layered authentication system supporting Cloudflare Access JWT verification, self-hosted Google OAuth for GSC/GA4 integration, API key validation for third-party services, and local development modes, orchestrated through middleware that injects user context into request handlers.**

OpenSEO is an open-source SEO platform that requires flexible authentication to support both cloud-hosted SaaS deployments and self-hosted instances. The authentication architecture balances enterprise-grade security with developer convenience, utilizing distinct strategies for production users, internal tools, and API integrations according to the every-app/open-seo source code.

## Auth Mode Detection and Strategy Selection

The authentication flow begins in [`src/lib/auth-mode.ts`](https://github.com/every-app/open-seo/blob/main/src/lib/auth-mode.ts), where the system determines which strategy applies to the current request. The `getAuthMode` function evaluates the runtime environment and headers to select between **Cloudflare Access** mode, **local no-auth** development mode, or **API-key-only** mode for external data providers.

This detection mechanism allows the same codebase to operate as a secure SaaS product under Cloudflare Access, a local development server without credentials, or a headless API consumer. When running in production, the system expects Cloudflare Access headers containing signed JWTs, while local development bypasses authentication entirely for convenience.

## Cloudflare Access JWT Verification

For production deployments, OpenSEO relies on **Cloudflare Access** to handle identity provider integration. The core verification logic resides in [`src/lib/auth.ts`](https://github.com/every-app/open-seo/blob/main/src/lib/auth.ts), which validates signed JWTs issued by Cloudflare Access and extracts user identity claims.

The middleware extracts the JWT from request headers, verifies the signature against Cloudflare's public keys, and populates `context.auth` with `userId`, `organizationId`, and permission scopes. This verification ensures that only authenticated users from authorized organizations can access protected endpoints.

```typescript
import { getAuthMode } from '@/lib/auth-mode';

export async function someServerFn(context) {
  const mode = getAuthMode(context);
  if (mode === 'cloudflare_access') {
    // JWT already verified – safe to use context.auth
    console.log('User', context.auth.userId);
  }
}

```

## Self-Hosted Google OAuth Implementation

When users connect **Google Search Console** (GSC) or **Google Analytics 4** (GA4), OpenSEO supports self-hosted OAuth configurations stored in [`src/server/features/google/oauth-config.ts`](https://github.com/every-app/open-seo/blob/main/src/server/features/google/oauth-config.ts). This approach allows self-hosted instances to maintain their own OAuth credentials rather than relying on a centralized SaaS authorization server.

The system checks for valid OAuth configurations using `hasSelfHostedGoogleOAuthConfig` before executing GSC or GA4 operations in [`src/shared/gsc.ts`](https://github.com/every-app/open-seo/blob/main/src/shared/gsc.ts) and [`src/shared/ga4.ts`](https://github.com/every-app/open-seo/blob/main/src/shared/ga4.ts). If the configuration is missing or invalid, the functions return a `gsc_oauth_not_configured` error, prompting the user to complete the OAuth setup.

## API Key Authentication for External Services

For integrations with third-party data providers like DataForSEO, OpenSEO implements **API key authentication** via [`src/lib/auth-api-key.ts`](https://github.com/every-app/open-seo/blob/main/src/lib/auth-api-key.ts). This validation layer checks the `x-dataforseo-key` header on incoming requests to verify the client has supplied valid credentials before proxying requests to external APIs.

```typescript
import { validateApiKey } from '@/lib/auth-api-key';

export async function handler(request) {
  const apiKey = request.headers.get('x-dataforseo-key');
  if (!validateApiKey(apiKey)) {
    return new Response('Invalid API key', { status: 401 });
  }
  // proceed with DataForSEO request
}

```

## Session Management and CAPTCHA Protection

OpenSEO maintains short-lived session cookies through [`src/lib/auth-session.ts`](https://github.com/every-app/open-seo/blob/main/src/lib/auth-session.ts) to persist authentication state across requests. For login flows exposed to the public internet, the system optionally enables **Cloudflare Turnstile** CAPTCHA verification via [`src/lib/auth-turnstile.ts`](https://github.com/every-app/open-seo/blob/main/src/lib/auth-turnstile.ts), protecting against automated abuse while maintaining a frictionless user experience.

## Middleware-Based User Context Injection

The `src/middleware/ensure-user/*` directory contains the critical middleware responsible for extracting authenticated users and resolving organization contexts. The `ensureUser` decorator wraps request handlers, guaranteeing that `context.auth` contains valid user and organization identifiers before executing business logic.

```typescript
import { ensureUser } from '@/middleware/ensure-user';

export const onRequest = ensureUser(async (request, context) => {
  // `context.auth` is guaranteed
  const { userId, organizationId } = context.auth;
  // …handle the request
});

```

This middleware pattern centralizes authentication enforcement, ensuring downstream services never handle unauthenticated requests while keeping route handlers clean and focused on business logic.

## MCP Project-Level Authorization

For internal tool operations and machine-to-machine communication, OpenSEO implements **MCP (Model Context Protocol) project authorization** through [`src/server/mcp/project-auth.ts`](https://github.com/every-app/open-seo/blob/main/src/server/mcp/project-auth.ts). The `withMcpProjectAuth` helper decorates tool functions, wrapping them with project-level permission checks before execution.

```typescript
import { withMcpProjectAuth } from '@/server/mcp/project-auth';

export const saveKeywords = withMcpProjectAuth(async (context, payload) => {
  // `context.auth` contains the authenticated user & org
  await db.keywords.insert({ ...payload, createdBy: context.auth.userId });
});

```

Files in `src/server/mcp/tools/*` utilize this wrapper to ensure that background jobs and automated operations run under the appropriate authorization context, preventing cross-project data access.

## Summary

- **OpenSEO** supports multiple authentication strategies including Cloudflare Access JWTs, local no-auth mode, and API key validation, selectable at runtime via [`src/lib/auth-mode.ts`](https://github.com/every-app/open-seo/blob/main/src/lib/auth-mode.ts).
- **Cloudflare Access** integration in [`src/lib/auth.ts`](https://github.com/every-app/open-seo/blob/main/src/lib/auth.ts) verifies signed JWTs and populates request context with user and organization identifiers.
- **Self-hosted Google OAuth** configuration in [`src/server/features/google/oauth-config.ts`](https://github.com/every-app/open-seo/blob/main/src/server/features/google/oauth-config.ts) enables standalone GSC and GA4 integrations without centralized SaaS dependencies.
- **API key validation** through [`src/lib/auth-api-key.ts`](https://github.com/every-app/open-seo/blob/main/src/lib/auth-api-key.ts) secures external data provider integrations via header inspection.
- The **ensure-user middleware** in `src/middleware/ensure-user/*` centralizes authentication enforcement by injecting verified auth contexts into all protected routes.
- **MCP project authorization** via [`src/server/mcp/project-auth.ts`](https://github.com/every-app/open-seo/blob/main/src/server/mcp/project-auth.ts) provides fine-grained access control for internal tools and automated workflows.

## Frequently Asked Questions

### How does OpenSEO authenticate users in production environments?

In production, OpenSEO uses Cloudflare Access to authenticate users via JWT tokens. The system validates these tokens in [`src/lib/auth.ts`](https://github.com/every-app/open-seo/blob/main/src/lib/auth.ts), extracting user and organization identifiers to populate the request context. This approach delegates identity provider management to Cloudflare while maintaining strict verification of signed claims.

### Can OpenSEO run without authentication for local development?

Yes. OpenSEO includes a local no-auth mode detected by `getAuthMode` in [`src/lib/auth-mode.ts`](https://github.com/every-app/open-seo/blob/main/src/lib/auth-mode.ts). When running in development environments without Cloudflare Access headers, the system creates a temporary admin context allowing unrestricted access to all features, facilitating rapid iteration without credential setup.

### How are Google Search Console and Analytics 4 credentials managed in OpenSEO?

Self-hosted instances store OAuth credentials in [`src/server/features/google/oauth-config.ts`](https://github.com/every-app/open-seo/blob/main/src/server/features/google/oauth-config.ts). The system validates these configurations using `hasSelfHostedGoogleOAuthConfig` before executing GSC or GA4 operations. If credentials are missing, operations return a `gsc_oauth_not_configured` error, prompting administrators to complete the OAuth flow.

### What is the role of the ensure-user middleware in the authentication flow?

The ensure-user middleware in `src/middleware/ensure-user/*` acts as a gatekeeper for protected routes. It extracts authentication data from requests, verifies the current auth mode, and injects a guaranteed `context.auth` object containing `userId` and `organizationId` into downstream handlers. This ensures consistent authorization enforcement across the application without duplicating validation logic in individual routes.