OmniRoute Authorization Pipeline and Route Classes: How Requests Are Validated

The OmniRoute authorization pipeline is a centralized middleware system in src/server/authz/pipeline.ts that intercepts every HTTP request to classify it into one of three route classes—PUBLIC, CLIENT_API, or MANAGEMENT—and enforce security policies before handlers execute.

The authorization pipeline in the diegosouzapw/OmniRoute repository ensures that every HTTP request undergoes a deterministic 14-step validation flow before reaching business logic. Located in src/server/authz/pipeline.ts, this system strips spoofed headers, validates body sizes, checks server drain state, and dispatches to class-specific policies. Understanding the pipeline architecture is essential for developers extending OmniRoute's security model or debugging authentication failures.

The Three Route Classes

OmniRoute categorizes every endpoint into a specific RouteClass defined in src/server/authz/types.ts (lines 20-21):

export type RouteClass = "PUBLIC" | "CLIENT_API" | "MANAGEMENT";

The classification logic resides in src/server/authz/classify.ts, which maps URL patterns and HTTP methods to these classes using prefix-based rules such as "public_prefix" or "dashboard_prefix". Each classification produces a RouteClassification object (defined in types.ts lines 42-52) that includes the route class and a normalized path for policy evaluation.

  • PUBLIC – Routes that are deliberately safe and require no authentication, such as health checks, login endpoints, and onboarding flows.
  • CLIENT_API – Model-serving endpoints including /api/v1/*, /api/v1beta/*, and Codex alias routes that require valid API key authentication.
  • MANAGEMENT – Dashboard, settings, provider-management, and administrative endpoints that use dashboard sessions or management-grade credentials.

Pipeline Execution Flow

The runAuthzPipeline function executes 14 deterministic steps for every request. These steps run sequentially in src/server/authz/pipeline.ts before any route handler receives the request:

  1. Generate request ID – generateRequestId() (lines 24-25) creates a unique correlation token for distributed tracing.
  2. Classify the route – classifyRoute() (lines 33-34) maps the request path and method to a RouteClass.
  3. Normalize pathname – The classification returns a normalizedPath (line 34) used for policy checks.
  4. CORS handling – Sets corsRelaxOrigin (lines 46-48) for client-API and read-only public endpoints.
  5. Drain check – If isDraining() (lines 50-55) returns true, the pipeline returns a 503 response immediately.
  6. Body-size guard – For non-GET/OPTIONS calls, checkBodySize() and getBodySizeLimit() (lines 57-68) validate against cached settings.
  7. Header sanitisation – Strips AUTHZ_TRUSTED_HEADERS (lines 70-74) from forwarded requests to prevent header spoofing.
  8. Peer locality stamping – classifyStampedPeerLocality() (lines 91-96) classifies the client IP as local, loopback, or remote and stores it in AUTHZ_HEADER_PEER_LOCALITY.
  9. OPTIONS pre-flight – Short-circuit 204 response for CORS pre-flight requests (lines 98-104).
  10. Policy evaluation – Selects a policy from the POLICIES map (lines 35-39) based on route class and executes policy.evaluate() (lines 31-33).
  11. Rejection handling – Failed policies trigger rejectionResponse() (lines 50-67) returning JSON errors with request IDs.
  12. Management CSRF check – For MANAGEMENT routes, validateBrowserMutationOrigin() and validateDashboardCsrfToken() (lines 44-58) enforce origin validation.
  13. Subject stamping – On success, stampSubject() (lines 41-48) encodes the authenticated subject into response headers.
  14. Forward request – Returns NextResponse.next() (lines 60-69) with sanitized headers to execute the route handler.

Working with the Authorization Pipeline

Route handlers in OmniRoute interact with the pipeline through specific imports that enforce or consume authorization data.

Enforcing Authorization in Route Handlers

Every API route imports runAuthzPipeline to enforce the authorization flow. The pipeline throws if the request is denied, otherwise it stamps authentication headers onto the request:

import { runAuthzPipeline } from "@/server/authz/pipeline";
import { NextRequest } from "next/server";

export async function GET(request: NextRequest) {
  // Enforce the pipeline (throws if the request is denied)
  const response = await runAuthzPipeline(request, { enforce: true });

  // If we reach here the request is authorised
  // request.headers now contains AUTHZ_HEADER_AUTH_ID, etc.
  const authId = request.headers.get("x-omniroute-auth-id");
  return new Response(`Authorized as ${authId}`);
}

This pattern is applied automatically to all /api/* routes because each handler imports runAuthzPipeline from the authorization layer.

Accessing Authenticated Subject Data

After pipeline execution, handlers use assertAuth to retrieve the strongly typed AuthSubject:

import { assertAuth } from "@/server/authz/assertAuth";
import type { AuthSubject } from "@/server/authz/types";

export async function POST(request: NextRequest) {
  const { subject }: { subject: AuthSubject } = await assertAuth(request);
  // `subject.kind` will be "client_api_key", "dashboard_session", etc.
  console.log("Authenticated:", subject);
  // … proceed with the actual business logic …
}

The assertAuth function reads the AUTHZ_HEADER_AUTH_* values that stampSubject (lines 41-48) injected into the request headers during pipeline execution.

Policy Architecture

Each route class maps to a specific policy implementation in the POLICIES dispatch table (lines 35-39 of pipeline.ts):

The pipeline uses header constants defined in src/server/authz/headers.ts for internal communication between steps, including AUTHZ_TRUSTED_HEADERS for sanitization and AUTHZ_HEADER_PEER_LOCALITY for IP classification.

Summary

  • The authorization pipeline in src/server/authz/pipeline.ts executes 14 sequential validation steps before any route handler runs.
  • Route classes (PUBLIC, CLIENT_API, MANAGEMENT) are defined in src/server/authz/types.ts and determined by src/server/authz/classify.ts.
  • The pipeline automatically sanitizes headers, checks body sizes, validates CORS, and stamps peer locality for every request.
  • Policy evaluation dispatches to class-specific implementations that return either an authenticated subject or a rejection response.
  • Route handlers consume stamped authentication data via assertAuth or directly from x-omniroute-auth-* headers.

Frequently Asked Questions

What are the three route classes in OmniRoute?

The three route classes are PUBLIC, CLIENT_API, and MANAGEMENT, defined as a TypeScript union type in src/server/authz/types.ts. PUBLIC routes require no authentication, CLIENT_API routes require valid API keys for model-serving endpoints, and MANAGEMENT routes require dashboard sessions or administrative credentials for configuration interfaces.

How does the OmniRoute pipeline handle CORS requests?

The pipeline sets a corsRelaxOrigin flag (lines 46-48) for client-API and read-only public endpoints during classification. For OPTIONS pre-flight requests, the pipeline short-circuits with a 204 response (lines 98-104) before reaching policy evaluation, ensuring CORS compliance without unnecessary authentication checks.

Where is the authorization pipeline implemented in OmniRoute?

The core implementation resides in src/server/authz/pipeline.ts, which exports the runAuthzPipeline function. Supporting files include src/server/authz/types.ts for type definitions, src/server/authz/classify.ts for route classification logic, and src/server/authz/policies/*.ts for class-specific authorization rules.

How do route handlers access authenticated subject data?

After runAuthzPipeline executes successfully, it stamps authentication data into request headers via stampSubject (lines 41-48). Route handlers then call assertAuth(request) from src/server/authz/assertAuth to retrieve a strongly typed AuthSubject object containing the user's identity, authentication kind (API key or session), and authorization scopes.

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 →