# OpenSEO Authentication Mechanisms: User Access, Project Scoping, and API Integration Security

> Explore OpenSEO authentication mechanisms: Cloudflare Access JWTs, project scoping, Google OAuth 2.0, Basic Auth, and local_noauth for secure user access and API integration.

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

---

**OpenSEO employs a layered authentication architecture combining Cloudflare Access JWTs for user sessions, project-level organization scoping via middleware, Google OAuth 2.0 for third-party integrations, and Basic Auth for DataForSEO API calls, with a `local_noauth` fallback for self-hosted deployments.**

The `every-app/open-seo` repository implements a robust, multi-layered authentication model that secures both the internal UI and external API integrations. Understanding these authentication mechanisms is critical for developers deploying self-hosted instances or integrating with the platform's DataForSEO-backed tooling. The system distinguishes between user-session authentication via Cloudflare Access, organization-scoped project authorization, and third-party service authentication using OAuth 2.0 and API keys.

## User Session Authentication: Cloudflare Access and Local Fallback

OpenSEO supports two distinct modes for authenticating user sessions, controlled by the configuration in [`src/lib/auth-mode.ts`](https://github.com/every-app/open-seo/blob/main/src/lib/auth-mode.ts).

### Cloudflare Access JWT Validation

For production deployments, OpenSEO uses **Cloudflare Access** to secure all server-function entry points. When a request arrives at the MCP transport layer in [`src/server/mcp/transport.ts`](https://github.com/every-app/open-seo/blob/main/src/server/mcp/transport.ts), the `getAuthenticatedContext` helper extracts and validates the signed JWT generated by Cloudflare Access.

The validated token attaches an `auth` object to the context containing:

- `userId`
- `userEmail`
- `organizationId`
- Token `scopes`

### Self-Hosted Local No-Auth Mode

For self-hosted deployments, the system provides a **`local_noauth`** fallback. In this mode, the middleware uses a static admin identity rather than validating external JWTs.

```typescript
// src/server/mcp/transport.ts
export async function handler(request: Request, context: RequestContext) {
  const { authMode } = context;
  if (authMode === "local_noauth") {
    // Admin identity for self-hosted mode
    context.auth = { userId: "admin", userEmail: "admin@localhost", organizationId: "local-org", scopes: [] };
  } else {
    const auth = getAuthenticatedContext(context);
    if (!auth) return new Response("MCP auth context required", { status: 403 });
    context.auth = auth;
  }
  // …continue handling
}

```

## Project-Level Organization Scoping

After user authentication, OpenSEO enforces **organization boundaries** through the `ensureUserMiddleware` defined in [`src/middleware/ensureUser.ts`](https://github.com/every-app/open-seo/blob/main/src/middleware/ensureUser.ts). This middleware resolves the project's organization and verifies the authenticated user belongs to that organization before allowing operations on specific projects.

```typescript
// src/middleware/ensureUser.ts
export const ensureUserMiddleware = createMiddleware({
  async before({ context }) {
    const auth = getAuthenticatedContext(context);
    if (!auth) throw new HttpError(401, "Unauthenticated");
    const project = await resolveProject(context.params.projectId, auth.organizationId);
    if (!project) throw new HttpError(403, "Project not in your org");
    return { auth, project };
  },
});

```

This project-scoping mechanism applies to all server functions in `src/serverFunctions/*` that operate on specific projects, ensuring users cannot access data outside their organizational boundaries.

## Google OAuth 2.0 Integration for Third-Party APIs

OpenSEO integrates with Google Search Console and Google Analytics 4 using **OAuth 2.0** authentication. The implementation resides in [`src/server/features/google/oauth-config.ts`](https://github.com/every-app/open-seo/blob/main/src/server/features/google/oauth-config.ts), which detects self-hosted Google OAuth configurations via the `hasSelfHostedGoogleOAuthConfig` function.

### Search Console and Analytics Authentication

When self-hosted OAuth is configured, the system uses stored refresh tokens to obtain access tokens with specific scopes:

- `https://www.googleapis.com/auth/webmasters.readonly` for Search Console
- `https://www.googleapis.com/auth/analytics.readonly` for GA4

```typescript
// src/serverFunctions/gsc.ts
import { hasSelfHostedGoogleOAuthConfig } from "@/server/features/google/oauth-config";

export const getGscData = serverFn(async (ctx) => {
  if (!hasSelfHostedGoogleOAuthConfig()) {
    throw new Error("gsc_oauth_not_configured");
  }
  const token = await getGoogleAccessToken(); // refresh token flow
  const res = await fetch("https://www.googleapis.com/webmasters/v3/sites", {
    headers: { Authorization: `Bearer ${token}` },
  });
  return await res.json();
});

```

The [`src/serverFunctions/ga4.ts`](https://github.com/every-app/open-seo/blob/main/src/serverFunctions/ga4.ts) file implements similar logic for Analytics 4 data retrieval, using the same OAuth configuration detection.

## DataForSEO API Authentication

For DataForSEO-backed tooling, OpenSEO uses **HTTP Basic Authentication** with API keys passed via environment variables. The credentials are never exposed in the client bundle and are accessed server-side in `src/server/mcp/tools/*`.

```typescript
// src/server/mcp/tools/site-audit-tools.ts
export async function fetchSiteAudit(context: McpContext, url: string) {
  const { baseUrl, apiKey, apiSecret } = context.auth;
  const response = await fetch(`${baseUrl}/site-audit`, {
    method: "POST",
    headers: {
      Authorization: `Basic ${btoa(`${apiKey}:${apiSecret}`)}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ url }),
  });
  return response.json();
}

```

## MCP Transport Layer and Token Scoping

The **MCP (Marketplace-API)** transport layer in [`src/server/mcp/transport.ts`](https://github.com/every-app/open-seo/blob/main/src/server/mcp/transport.ts) validates Bearer tokens from the `Authorization` header. It extracts the `organizationId` and required scopes, injecting the same `auth` object used by the UI middleware to ensure consistent authorization across all entry points.

Requests include `Authorization: Bearer <token>` headers, and the transport validates these tokens before processing tool invocations, ensuring that billing and quota enforcement remain tied to the correct organization.

## Summary

- **Cloudflare Access** or `local_noauth` handles user-session authentication via JWT validation in [`src/server/mcp/transport.ts`](https://github.com/every-app/open-seo/blob/main/src/server/mcp/transport.ts)
- **Project scoping** enforces organization boundaries through `ensureUserMiddleware` in [`src/middleware/ensureUser.ts`](https://github.com/every-app/open-seo/blob/main/src/middleware/ensureUser.ts)
- **Google OAuth 2.0** provides secure access to Search Console and Analytics 4 data using refresh tokens configured in [`src/server/features/google/oauth-config.ts`](https://github.com/every-app/open-seo/blob/main/src/server/features/google/oauth-config.ts)
- **DataForSEO API keys** use HTTP Basic Auth via server-side environment variables, accessible in `src/server/mcp/tools/*`
- All authentication flows propagate the `organizationId` to ensure correct billing and quota enforcement across the platform

## Frequently Asked Questions

### How does OpenSEO handle authentication in self-hosted environments?

Self-hosted deployments use the `local_noauth` mode defined in [`src/lib/auth-mode.ts`](https://github.com/every-app/open-seo/blob/main/src/lib/auth-mode.ts), which bypasses Cloudflare Access and assigns a static admin identity with `userId: "admin"` and `organizationId: "local-org"`. This allows single-user or development instances to function without external identity providers while maintaining the same authorization structure as production deployments.

### What OAuth scopes does OpenSEO request for Google integrations?

OpenSEO requests read-only scopes for Google services: `https://www.googleapis.com/auth/webmasters.readonly` for Search Console data and `https://www.googleapis.com/auth/analytics.readonly` for Google Analytics 4. These scopes restrict the application to read-only access of site performance data without write permissions.

### How is the DataForSEO API key secured?

The DataForSEO API credentials are stored in environment variables on the server and accessed only through server-side tool implementations in `src/server/mcp/tools/*`. The keys are never bundled in client-side JavaScript, and all API requests use HTTP Basic Authentication headers generated server-side using `btoa()` encoding of the key and secret combination.

### How does project-level authorization prevent cross-organization access?

The `ensureUserMiddleware` in [`src/middleware/ensureUser.ts`](https://github.com/every-app/open-seo/blob/main/src/middleware/ensureUser.ts) resolves the project using the request's `projectId` parameter and validates that the project's organization matches the authenticated user's `organizationId`. If the organizations do not match, the middleware throws a 403 error, preventing users from accessing projects outside their organizational scope.