# OmniRoute Authentication and Authorization Pipeline: Route Classes Explained

> Understand the OmniRoute authentication and authorization pipeline. Learn how PUBLIC, CLIENT_API, and MANAGEMENT route classes handle request authentication and authorization decisions.

- Repository: [Diego Rodrigues de Sa e Souza/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- Tags: deep-dive
- Published: 2026-08-04

---

**OmniRoute uses a centralized middleware pipeline in [`src/server/authz/pipeline.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/server/authz/pipeline.ts) that classifies every request into one of three route classes—PUBLIC, CLIENT_API, or MANAGEMENT—and delegates authentication to specialized policies that return a simple allow/reject decision before stamping the validated subject into response headers.**

The **OmniRoute** routing platform implements a strict **authentication and authorization pipeline** that intercepts every incoming request to enforce security boundaries. By categorizing endpoints into three distinct **route classes**, the system applies granular access controls while maintaining consistent CORS, IP filtering, and tracing logic across health checks, SDK-facing APIs, and dashboard operations.

## The Three Route Classes

The `classifyRoute` function in [`src/server/authz/classify.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/server/authz/classify.ts) examines the URL pathname and HTTP method to assign a **route class** that determines acceptable authentication methods:

- **PUBLIC** – Read-only endpoints such as health checks and provider catalogs. These may allow anonymous access or optional Bearer tokens depending on the `REQUIRE_API_KEY` configuration.
- **CLIENT_API** – Standard REST endpoints under `/v1/*` consumed by SDKs, CLI tools, and browser clients. Requires API keys, Bearer tokens, or valid dashboard sessions.
- **MANAGEMENT** – Dashboard UI, MCP tools, and internal operations requiring dashboard-session cookies, management-scope API keys, CLI tokens, or special bridge secrets.

## Pipeline Execution Flow

The `runAuthzPipeline` function in [`src/server/authz/pipeline.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/server/authz/pipeline.ts) processes every request through fourteen discrete stages before reaching the downstream handler. This centralized approach ensures that cross-cutting security concerns execute in a predictable order.

### Phase 1: Request Initialization and Classification

The pipeline first generates a UUID via `generateRequestId` and assigns it to the response for distributed tracing. It then calls `classifyRoute` to determine the **route class** and normalized path, storing these in the `AUTHZ_HEADER_ROUTE_CLASS` and `AUTHZ_HEADER_REQUEST_ID` headers. For non-loopback requests, the `classifyStampedPeerLocality` helper stamps whether the peer is `loopback`, `remote`, or another classification.

### Phase 2: Pre-Flight Security Checks

Before authentication occurs, the pipeline performs several safety validations:

1. **CORS handling** – For `CLIENT_API` and read-only `PUBLIC` routes, `corsRelaxOrigin` relaxes the `Origin` header to allow browser and Electron clients without credentials.
2. **Graceful shutdown guard** – If the server is draining (`isDraining`), the pipeline returns an immediate **503** response.
3. **Body size validation** – For non-GET/OPTIONS requests, `checkBodySize` validates the payload against cached settings.
4. **Header sanitization** – The pipeline strips trusted headers like peer-IP stamps from forwarded requests to prevent spoofing, as implemented in the header stripping loop at lines 102‑110.

### Phase 3: Policy Evaluation

When `options.enforce` is **true**, the pipeline selects a policy from the `POLICIES` map based on the route class and evaluates it against a `PolicyContext`:

- **`publicPolicy`** for PUBLIC routes
- **`clientApiPolicy`** for CLIENT_API routes
- **`managementPolicy`** for MANAGEMENT routes

Each policy returns an **`AuthOutcome`** object containing either an `allow` status with the authenticated subject or a `reject` status with an error code.

### Phase 4: Post-Authentication Controls

For denied requests, the `rejectionResponse` helper returns a JSON payload with `code`, `message`, and `correlation_id`. Dashboard rejections trigger a redirect to the login page.

For allowed MANAGEMENT requests, additional protections apply:

- **CSRF validation** – State-changing methods (`POST`, `PUT`, `DELETE`) validate the `Origin` header and fall back to a dashboard CSRF token via the CSRF block at lines 76‑89.
- **Subject stamping** – The `stampSubject` function writes the authentication kind (`dashboard_session`, `client_api_key`, `management_key`, etc.) into response headers including `AUTHZ_HEADER_AUTH_KIND` and `AUTHZ_HEADER_AUTH_ID`.

Finally, the pipeline returns `NextResponse.next()` with enriched headers, applying CORS policies and optionally refreshing the dashboard JWT cookie.

## Route Class Policy Implementation

### PUBLIC Policy

The `publicPolicy` in [`src/server/authz/policies/public.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/server/authz/policies/public.ts) defaults to permissive for **read-only** endpoints, allowing anonymous access. For non-read-only operations classified as PUBLIC, it delegates to the same Bearer/API-key validation logic used by `clientApiPolicy` unless explicitly marked as public-readonly.

### CLIENT_API Policy

Located in [`src/server/authz/policies/clientApi.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/server/authz/policies/clientApi.ts), the `clientApiPolicy` accepts credentials from multiple sources:

- `Authorization: Bearer <token>`
- `x-api-key` or `x-goog-api-key` headers
- Legacy CLI token headers

If no token is present, the policy allows:
- WebSocket handshake requests (`/api/v1/ws`)
- Valid dashboard sessions
- Anonymous access when `REQUIRE_API_KEY` is disabled

When a token exists, `validateApiKey` checks it against the API-key table. Success grants access as `client_api_key`; failure rejects with **401 AUTH_002** unless `REQUIRE_API_KEY` is off, in which case it degrades to anonymous.

### MANAGEMENT Policy

The `managementPolicy` in [`src/server/authz/policies/management.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/server/authz/policies/management.ts) implements a tiered authentication hierarchy for privileged operations:

1. **WS-bridge secret** – Validates the `OMNIROUTE_WS_BRIDGE_SECRET` for internal process communication.
2. **LOCAL_ONLY bypass** – Certain paths allow non-loopback access only with a **manage-scope API key** or authenticated dashboard session.
3. **Internal tokens** – Supports inspector ingest tokens and internal model-sync requests.
4. **CLI token** – Loopback-only authentication via `CLI_TOKEN_HEADER`.
5. **Optional auth-disabled paths** – Allows anonymous when `isAuthRequired` is false.
6. **Dashboard session** – Cookie-based session validation.
7. **Access tokens** – Validates `oma_` prefixed tokens via `evaluateAccessTokenAuth`.
8. **Management API keys** – Requires `manage`, `admin`, or `mcp:connect` scope for `/api/mcp/*` paths.

Invalid Bearer tokens result in **403**; missing credentials result in **401**.

## Security Mechanisms and Middleware Integration

### IP Filtering and Peer Validation

After classification, `checkRequestIP` evaluates the external IP against operator-defined blacklists and whitelists for all non-loopback requests, as seen at lines 146‑160 of the pipeline.

### Middleware Configuration

To enforce the pipeline across all API routes, implement the following middleware in your Next.js application:

```typescript
// src/middleware/authz.ts
import { runAuthzPipeline } from '@/server/authz/pipeline';
import type { NextRequest } from 'next/server';

export async function middleware(request: NextRequest) {
  // Enforce the full authz pipeline for every request.
  // The `enforce: true` flag triggers policy evaluation.
  return await runAuthzPipeline(request, { enforce: true });
}

```

Apply this middleware to the `/api/**` route matcher to ensure consistent security headers and authentication checks across the entire API surface.

## Summary

- OmniRoute uses **three route classes** (PUBLIC, CLIENT_API, MANAGEMENT) to apply distinct authentication requirements based on endpoint sensitivity.
- The **authorization pipeline** in [`src/server/authz/pipeline.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/server/authz/pipeline.ts) centralizes CORS, body-size limits, IP filtering, and header sanitization before delegating to policy-specific logic.
- **Policy modules** are composable functions returning `AuthOutcome` objects, making the system testable and extensible.
- Authentication results are stamped into response headers (`AUTHZ_HEADER_AUTH_KIND`, `AUTHZ_HEADER_AUTH_ID`) for downstream audit logging and service consumption.
- **CSRF protection** and **session refresh** are automatically applied to MANAGEMENT route mutations, while PUBLIC routes remain open for health checks and metadata access.

## Frequently Asked Questions

### What is the difference between CLIENT_API and MANAGEMENT route classes?

**CLIENT_API** routes are designed for external SDK and CLI consumption, accepting scoped API keys and Bearer tokens for specific resources. **MANAGEMENT** routes control dashboard access and internal operations, requiring broader permissions such as `manage` or `admin` scope, dashboard sessions, or internal bridge secrets. The MANAGEMENT policy also enforces additional CSRF protection for state-changing operations that CLIENT_API does not require.

### How does OmniRoute handle anonymous access to PUBLIC endpoints?

The `publicPolicy` allows anonymous access specifically for **read-only** operations like health checks and catalog listings. If a PUBLIC endpoint performs non-read operations, the policy falls back to the same API-key validation used by CLIENT_API unless explicitly configured otherwise via `REQUIRE_API_KEY` settings.

### What authentication methods are supported for MANAGEMENT routes?

MANAGEMENT routes support ten distinct authentication methods evaluated in strict order: WS-bridge secrets, LOCAL_ONLY bypass with management keys, inspector ingest tokens, internal model-sync requests, loopback CLI tokens, auth-disabled path exceptions, dashboard sessions, `oma_` access tokens, management-scope API keys, and OAuth Bearer tokens. This hierarchy allows both automated internal services and human operators to access dashboard functionality through appropriate credentials.

### Where is the authentication outcome recorded for downstream services?

After successful policy evaluation, the `stampSubject` function writes the authentication results into response headers including `AUTHZ_HEADER_AUTH_KIND` (e.g., `dashboard_session`, `client_api_key`), `AUTHZ_HEADER_AUTH_ID` (the masked identifier), and `AUTHZ_HEADER_REQUEST_ID` for correlation. These headers allow upstream proxies and logging services to identify the caller without re-validating the token.