OpenSEO Authentication Modes: Configuring Cloudflare Access, Local, and Hosted Auth

OpenSEO supports three authentication modes—cloudflare_access for Cloudflare Zero-Trust, local_noauth for development, and hosted for the managed SaaS platform—configured exclusively via the AUTH_MODE environment variable.

OpenSEO, the open-source SEO platform from every-app/open-seo, implements a flexible authentication architecture that adapts to different deployment environments without code changes. The system determines which authentication strategy to apply at runtime through the Auth_MODE environment variable, enabling the same codebase to operate as a secure SaaS application, a Cloudflare-protected self-hosted instance, or a credential-free local development server.

The Three OpenSEO Authentication Modes

OpenSEO determines user identity and authorization scope through the AuthMode type defined in src/lib/auth-mode.ts. Each mode handles request validation differently based on your infrastructure requirements.

cloudflare_access (Self-Hosted with Zero-Trust)

Use cloudflare_access when deploying a self-hosted instance that relies on Cloudflare Access for identity management. In this mode, Cloudflare Access injects an Authorization header containing a signed JWT into each request. The OpenSEO server validates this token and extracts the user's identity and permission scopes. This approach delegates all authentication decisions to Cloudflare's edge network, making it ideal for internal tools or teams already using Cloudflare Zero-Trust.

local_noauth (Local Development)

Set AUTH_MODE to local_noauth for local development or testing scenarios where authentication must be bypassed. When active, OpenSEO treats all incoming requests as originating from an internal admin user, requiring no authentication headers. This mode eliminates the need to configure external identity providers during rapid prototyping, though it should never be used in production environments.

hosted (Managed SaaS Platform)

The hosted mode powers the official SaaS version of OpenSEO running on Every App's managed platform. Users authenticate through the hosted UI via an OAuth flow managed by the platform. The server reads the session cookie or JWT that the platform sets on each request, automatically authorizing users without additional configuration. This mode is the default for the managed service and handles multi-tenant user isolation.

Configuring the AUTH_MODE Environment Variable

Authentication mode selection happens at runtime through environment variable configuration. No code changes or rebuilds are required to switch between modes.

Set the variable in your deployment environment:


# Self-hosted with Cloudflare Access

AUTH_MODE=cloudflare_access

# Local development (no auth)

AUTH_MODE=local_noauth

# Hosted SaaS (managed platform)

AUTH_MODE=hosted

For cloudflare_access deployments, you must additionally configure a Cloudflare Access Application and define the required authentication policies in your Cloudflare dashboard. The local_noauth mode requires no external setup, while hosted mode requires deployment to the Every App platform infrastructure. Verify the active mode at runtime using the /api/oauth/consent endpoint or the whoami tool available in the MCP transport layer.

Implementing Auth Mode Checks in Code

The core library provides type-safe utilities to branch logic based on the active authentication strategy. All helpers reside in src/lib/auth-mode.ts.

Resolving the Current Mode

Use getAuthMode to parse and normalize the environment variable value. This function accepts either process.env.AUTH_MODE on the server or import.meta.env.AUTH_MODE in client bundles:

import { getAuthMode } from "@/lib/auth-mode";

export async function handler(request: Request) {
  const authMode = getAuthMode(process.env.AUTH_MODE);
  console.log("Running in auth mode:", authMode);
  // Branch logic based on authMode value
}

Using Predicate Functions

Helper predicates simplify conditional logic without hardcoding string comparisons:

import { getAuthMode, isHostedAuthMode, isHostedClientAuthMode, isEmailVerificationBypassed } from "@/lib/auth-mode";

const mode = getAuthMode(import.meta.env.AUTH_MODE);

if (isHostedAuthMode(mode)) {
  // Execute hosted SaaS specific logic
}

if (isEmailVerificationBypassed()) {
  // Skip verification steps in local development
}

if (isHostedClientAuthMode()) {
  // Client-side safeguard ensuring build-time AUTH_MODE matches runtime
}

Server-Side Route Protection

The middleware layer uses these checks to enforce authentication requirements. In src/middleware/ensure-user/resolve.ts, the system uses the auth mode to decide whether to enforce user authentication for a given request. Similarly, src/server.ts reads AUTH_MODE at startup to select the appropriate request-handling path for hosted versus self-hosted deployments.

Core Files Handling Authentication Logic

Understanding the source file organization helps when customizing authentication behavior:

  • src/lib/auth-mode.ts — Defines the AuthMode union type, the getAuthMode parsing logic, and all predicate helper functions including isHostedAuthMode and isEmailVerificationBypassed.

  • src/server.ts — Reads AUTH_MODE at application startup and initializes the appropriate request routing pipeline for hosted or self-hosted operation.

  • src/middleware/ensure-user/resolve.ts — Contains the authentication enforcement logic that references the current mode to determine if a request requires a valid user session.

  • src/server/mcp/transport.ts — Implements mode-aware request handling for internal MCP (Model Context Protocol) APIs, using the whoami verification tool.

  • docs/SELF_HOSTING_DOCKER.md — Deployment documentation providing practical guidance on setting AUTH_MODE in containerized environments.

Summary

  • OpenSEO provides three authentication strategies: cloudflare_access for Cloudflare Zero-Trust, local_noauth for development, and hosted for the SaaS platform.
  • Configuration occurs exclusively through the AUTH_MODE environment variable, requiring no code modifications to switch modes.
  • The getAuthMode function in src/lib/auth-mode.ts normalizes environment variable values into type-safe AuthMode types.
  • Predicate helpers like isHostedAuthMode and isEmailVerificationBypassed enable clean conditional logic without string comparisons.
  • Production deployments using cloudflare_access require additional Cloudflare Access Application configuration, while local_noauth is strictly for development use.

Frequently Asked Questions

What are the valid AUTH_MODE values in OpenSEO?

OpenSEO accepts three string values for AUTH_MODE: cloudflare_access for Cloudflare Zero-Trust integration, local_noauth for credential-free development, and hosted for the managed Every App platform. The getAuthMode function in src/lib/auth-mode.ts validates and normalizes these values at runtime, throwing an error if an unsupported mode is specified.

How does Cloudflare Access authentication work technically?

When AUTH_MODE is set to cloudflare_access, OpenSEO expects Cloudflare's edge network to validate users before requests reach the application. Cloudflare injects a signed JWT in the Authorization header, which OpenSEO validates to extract identity claims and scopes. This moves authentication to the network edge, ensuring unauthenticated requests never reach your origin server.

Is local_noauth safe for production environments?

No, local_noauth is explicitly designed for local development and testing only. When enabled, OpenSEO treats all requests as coming from an admin user without verifying credentials, creating significant security vulnerabilities if exposed to the internet. Production deployments should use either cloudflare_access or the hosted mode on the managed platform.

How can I detect the current authentication mode in client-side code?

Use getAuthMode(import.meta.env.AUTH_MODE) to safely retrieve the mode in browser contexts, or use the isHostedClientAuthMode() predicate for build-time checks. These utilities ensure your client-side logic respects the same authentication configuration as the server, preventing mismatches between the build environment and runtime deployment.

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 →