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

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, 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, 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.

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. 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 and 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. 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.

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 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, 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.

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. The withMcpProjectAuth helper decorates tool functions, wrapping them with project-level permission checks before execution.

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.
  • Cloudflare Access integration in 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 enables standalone GSC and GA4 integrations without centralized SaaS dependencies.
  • API key validation through 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 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, 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. 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. 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.

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 →