# OpenSEO Chat Agents Authorization: How Access Control Works in the OpenSEO Source Code

> Understand OpenSEO Chat Agents authorization. Learn how access control works in the OpenSEO source code, requiring authenticated user sessions and specific organization links.

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

---

**Both OpenSEO chat agents require an authenticated user session linked to the correct organization, enforced via session cookies/JWT in hosted deployments or Cloudflare Access tokens in self-hosted mode.**

The **open-seo** repository by every-app implements a multi-layered authorization system for its WebSocket-based chat agents. This article examines the exact authorization requirements, source code implementation, and configuration options that protect the **SamChatAgent** and **OnboardingChatAgent** from unauthorized access.

## How OpenSEO Chat Agents Authorization Is Structured

The authorization flow centers on a single entry point in [`src/server.ts`](https://github.com/every-app/open-seo/blob/main/src/server.ts) that branches based on agent type. All requests—whether WebSocket upgrades or standard HTTP fetches—must pass through this gate before reaching the underlying Durable Object.

### The `authorizeChatAgent` Gate Function

Located at [lines 101-108 of [`src/server.ts`](https://github.com/every-app/open-seo/blob/main/src/server.ts)](https://github.com/every-app/open-seo/blob/main/src/server.ts#L101-L108), `authorizeChatAgent` serves as the unified authorization dispatcher:

```typescript
function authorizeChatAgent(request: Request, lobby: { className: string }) {
  switch (lobby.className) {
    case "SAM_CHAT":
      return authorizeSamChat(request);
    case "ONBOARDING_CHAT":
      return authorizeOnboardingChat(request);
    default:
      return new Response("Forbidden", { status: 403 });
  }
}

```

This function extracts the `className` from the lobby configuration and delegates to the appropriate specialized authorizer. Any unrecognized agent type immediately returns **403 Forbidden**.

## What Credentials OpenSEO Chat Agents Validate

Both `authorizeSamChat` and `authorizeOnboardingChat` perform identical authorization checks according to the source code in [`src/server.ts`](https://github.com/every-app/open-seo/blob/main/src/server.ts). These checks ensure only legitimate users access organizational chat data.

### Required Authentication Components

- **Valid session identification** – The authorizer extracts a session cookie or JWT token from the request headers
- **Organization ownership verification** – The resolved `sessionId` must map to a user belonging to the organization that owns the target Durable Object
- **Self-hosted mode compliance** – Additional environment-specific checks based on `AUTH_MODE` configuration

### Authorization Failure Handling

When any check fails, the authorizer returns a **403 Forbidden** response before the request reaches the chat agent Durable Object. This prevents unauthorized WebSocket connections and HTTP API calls at the edge.

## Self-Hosted Deployment Authorization Modes

OpenSEO supports three authentication configurations controlled by the `AUTH_MODE` environment variable. These modes determine how strictly the chat agent authorization layer enforces access control.

| Mode | Authorization Behavior | Use Case |
|------|------------------------|----------|
| **Default (hosted)** | Standard session cookie/JWT validation against user database | every-app cloud platform |
| `cloudflare_access` | Validates Cloudflare Access token in addition to session checks | Self-hosted with Cloudflare Access |
| `local_noauth` | Bypasses authentication entirely for local development | Local development only |

The `authorizeSamChat` and `authorizeOnboardingChat` functions reference `AUTH_MODE` to apply these variations, as implemented in [`src/server.ts`](https://github.com/every-app/open-seo/blob/main/src/server.ts).

## Routing After OpenSEO Chat Agents Authorization

Successful authorization permits the request to proceed through `routeChatAgents`, which handles both WebSocket upgrades and HTTP fetch requests. This routing logic appears at [lines 55-60 of [`src/server.ts`](https://github.com/every-app/open-seo/blob/main/src/server.ts)](https://github.com/every-app/open-seo/blob/main/src/server.ts#L55-L60):

```typescript
await routeAgentRequest(request, env, {
  onBeforeConnect: (req, lobby) => authorizeChatAgent(req, lobby),
  onBeforeRequest: (req, lobby) => authorizeChatAgent(req, lobby),
});

```

Two distinct hooks ensure authorization runs:

- `onBeforeConnect` – Executes before WebSocket upgrade for real-time chat connections
- `onBeforeRequest` – Executes before standard HTTP requests to the chat agent API

Both hooks invoke the same `authorizeChatAgent` function, maintaining consistent security across transport protocols.

## Key Source Files for OpenSEO Chat Agents Authorization

| File Path | Purpose |
|-----------|---------|
| [[`src/server.ts`](https://github.com/every-app/open-seo/blob/main/src/server.ts)](https://github.com/every-app/open-seo/blob/main/src/server.ts) | Core routing, `authorizeChatAgent`, and `routeChatAgents` implementation |
| [[`src/server/features/sam/SamChatAgent.ts`](https://github.com/every-app/open-seo/blob/main/src/server/features/sam/SamChatAgent.ts)](https://github.com/every-app/open-seo/blob/main/src/server/features/sam/SamChatAgent.ts) | SAM chat Durable Object |
| [[`src/server/features/onboarding/OnboardingChatAgent.ts`](https://github.com/every-app/open-seo/blob/main/src/server/features/onboarding/OnboardingChatAgent.ts)](https://github.com/every-app/open-seo/blob/main/src/server/features/onboarding/OnboardingChatAgent.ts) | Onboarding chat Durable Object |
| [`src/middleware/ensure-user/`](https://github.com/every-app/open-seo/tree/main/src/middleware/ensure-user) | Session extraction and user validation utilities |

## Summary

- **OpenSEO chat agents require authenticated sessions** – No public access; all requests must present valid credentials
- **Authorization splits by agent type** – `authorizeChatAgent` dispatches to `authorizeSamChat` or `authorizeOnboardingChat` based on `lobby.className`
- **Organization scoping is mandatory** – Sessions must belong to the organization owning the target Durable Object
- **Self-hosted flexibility** – `AUTH_MODE` supports Cloudflare Access integration or local development bypass
- **Dual-path protection** – Both WebSocket connections and HTTP requests pass through identical authorization checks

## Frequently Asked Questions

### What happens if I try to connect to an OpenSEO chat agent without authentication?

The connection is rejected with a **403 Forbidden** response before reaching the Durable Object. The `authorizeChatAgent` function returns this status when no valid session is found or when the session's organization doesn't match the target agent's organization.

### Can I disable authentication for OpenSEO chat agents in development?

Yes, by setting `AUTH_MODE=local_noauth` in your environment configuration. According to the source code in [`src/server.ts`](https://github.com/every-app/open-seo/blob/main/src/server.ts), this mode bypasses the standard session validation. This configuration is intended **only for local development** and should never be used in production deployments.

### Does OpenSEO chat agents authorization work differently for WebSocket versus HTTP requests?

No, both transport types use identical authorization logic. The `routeAgentRequest` function in [`src/server.ts`](https://github.com/every-app/open-seo/blob/main/src/server.ts) applies `authorizeChatAgent` through both `onBeforeConnect` (WebSocket) and `onBeforeRequest` (HTTP) hooks, ensuring consistent security regardless of how clients interact with the chat agents.

### What identifies which authorization path a request takes?

The `className` property of the `lobby` object determines the path. `SAM_CHAT` routes to `authorizeSamChat`; `ONBOARDING_CHAT` routes to `authorizeOnboardingChat`. Any other value triggers an immediate 403 response from the `authorizeChatAgent` dispatcher.