How the OmniRoute Authorization Pipeline Classifies Routes: A Deep Dive into Route Security Zones

OmniRoute's authorization pipeline classifies every incoming request into one of three security zones—PUBLIC, CLIENT_API, or MANAGEMENT—using the classifyRoute function in src/server/authz/classify.ts, which applies a three-stage evaluation process to determine which access policy governs the request.

The classification system serves as the foundation of OmniRoute's security model, determining whether a route requires authentication, CSRF protection, or specific scopes. By analyzing the request path and HTTP method before any authorization checks occur, the pipeline ensures that public endpoints remain accessible while protecting sensitive management and client API resources.

Core Classification Logic in classify.ts

The entry point for all route classification is src/server/authz/classify.ts, which exports the primary classification function used by the authorization middleware.

The classifyRoute Function Signature

The classification process begins with a single exported function that inspects the incoming request:

export function classifyRoute(rawPath: string, method: string = "GET"): RouteClassification

This function accepts the raw request path and HTTP method, then returns a RouteClassification object that the pipeline uses to select the appropriate security policy.

The RouteClassification Object

The function returns an object containing three critical properties:

  • routeClass – A string literal of either "PUBLIC", "CLIENT_API", or "MANAGEMENT" indicating the security zone.
  • reason – A descriptive string explaining the classification rationale (e.g., root_redirect, public_prefix, client_api_alias).
  • normalizedPath – The canonical pathname after alias resolution and trailing-slash cleanup.

These types are defined in src/server/authz/types.ts, which provides the TypeScript interfaces for the entire authorization system.

The Three-Stage Classification Process

The classifyRoute function operates through three sequential stages, with each stage potentially determining the final classification.

Stage 1: Path Normalization and Alias Handling

First, the normalizePathname helper ensures path consistency. It guarantees the path starts with /, removes trailing slashes, and rewrites known aliases. For example:

  • /v1/api/v1
  • /chat/completions/api/v1/chat/completions

When an alias is applied, the reason field records either client_api_alias or client_api_double_prefix, ensuring traceability for debugging.

Stage 2: Static Route Checks

After normalization, the function checks against hard-coded route patterns in priority order:

  • /MANAGEMENT with reason root_redirect
  • /dashboard/onboardingPUBLIC with reason setup_wizard
  • /connect…PUBLIC with reason public_connect_page
  • Any path beginning with /dashboardMANAGEMENT with reason dashboard_prefix

These static checks handle core application pages before evaluating API routes.

Stage 3: API-Prefix and Whitelist Evaluation

For paths starting with /api/, the classification applies specific prefix rules:

  1. Client API Detection – Paths starting with /api/v1 or /api/v1beta are automatically classified as CLIENT_API with reasons like client_api_v1.

  2. Public API Evaluation – For other /api/… paths, the helper isPublicApiRoute (imported from src/shared/constants/publicApiRoutes.ts) evaluates two whitelists:

    • PUBLIC_READONLY_API_ROUTE_PREFIXES combined with PUBLIC_READONLY_METHODS – for read-only public endpoints
    • PUBLIC_READWRITE_API_ROUTE_PREFIXES – for writable public endpoints
  3. Management Fallback – If no public rules match, the route defaults to MANAGEMENT with reason management_api.

If no rule matches across all stages, the function defaults to MANAGEMENT with reason fallback_management.

Integration with the Authorization Pipeline

The classification result flows directly into src/server/authz/pipeline.ts, which orchestrates the complete request authorization flow. Based on the routeClass property, the pipeline selects the appropriate RoutePolicy:

  • publicPolicy – Minimal security, no authentication required
  • clientApiPolicy – API-key authentication with optional scope validation
  • managementPolicy – Full session authentication, CSRF protection, and admin scope requirements

This architecture ensures that classification decisions made in classify.ts directly determine which authentication mechanisms and security headers apply to the request.

Practical Classification Examples

The following TypeScript examples demonstrate how various paths are classified according to the OmniRoute source code:

import { classifyRoute } from "@/server/authz/classify";

const examples = [
  { path: "/", method: "GET" },
  { path: "/dashboard/settings", method: "GET" },
  { path: "/v1/chat/completions", method: "POST" },
  { path: "/connect/abc123", method: "GET" },
  { path: "/api/v1/models", method: "GET" },
  { path: "/api/internal/secret", method: "POST" },
];

examples.forEach(({ path, method }) => {
  const result = classifyRoute(path, method);
  console.log(
    `${method} ${path} → ${result.routeClass} (reason: ${result.reason})`,
  );
});

/* Sample output:
GET / → MANAGEMENT (reason: root_redirect)
GET /dashboard/settings → MANAGEMENT (reason: dashboard_prefix)
POST /v1/chat/completions → CLIENT_API (reason: client_api_alias)
GET /connect/abc123 → PUBLIC (reason: public_connect_page)
GET /api/v1/models → CLIENT_API (reason: client_api_v1)
POST /api/internal/secret → MANAGEMENT (reason: management_api)
*/

Summary

  • Route classification occurs in src/server/authz/classify.ts via the classifyRoute function, which categorizes every request as PUBLIC, CLIENT_API, or MANAGEMENT.
  • Three-stage processing includes path normalization/alias handling, static route checks for dashboard pages, and API-prefix evaluation against whitelists.
  • Default security falls back to MANAGEMENT whenever no explicit rules match, ensuring secure-by-default behavior.
  • Pipeline integration means classification results directly determine which authorization policy (publicPolicy, clientApiPolicy, or managementPolicy) enforces the request in src/server/authz/pipeline.ts.
  • Public API routes are defined in src/shared/constants/publicApiRoutes.ts using prefix and method whitelists rather than explicit route registration.

Frequently Asked Questions

What are the three route classes in OmniRoute?

OmniRoute recognizes PUBLIC (unauthenticated endpoints like connect pages), CLIENT_API (versioned API endpoints under /api/v1 or /api/v1beta), and MANAGEMENT (dashboard and internal administrative interfaces). Each class triggers different authentication requirements and security headers when processed by the authorization pipeline.

How does OmniRoute handle API route aliases?

The normalizePathname function in src/server/authz/classify.ts automatically rewrites legacy or convenience paths to their canonical equivalents. For instance, /v1/chat/completions becomes /api/v1/chat/completions before classification occurs, with the reason field set to client_api_alias to indicate the transformation.

What happens if a route doesn't match any classification rules?

When no static rules, API prefixes, or whitelist entries match the request path, the classifyRoute function returns MANAGEMENT with the reason fallback_management. This secure-by-default approach ensures that unclassified endpoints receive the highest level of protection rather than unintentional public exposure.

Where are public API routes defined in OmniRoute?

Public API routes are declared in src/shared/constants/publicApiRoutes.ts, which exports the isPublicApiRoute helper function. This file maintains two whitelists—PUBLIC_READONLY_API_ROUTE_PREFIXES for read-only operations and PUBLIC_READWRITE_API_ROUTE_PREFIXES for writable endpoints—that determine whether an /api/ route should be classified as PUBLIC or MANAGEMENT.

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 →