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

> Learn how OmniRoute's authorization pipeline classifies routes into PUBLIC, CLIENT_API, or MANAGEMENT security zones. Understand the three-stage evaluation process for route security.

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

---

**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`](https://github.com/diegosouzapw/OmniRoute/blob/main/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`](https://github.com/diegosouzapw/OmniRoute/blob/main/classify.ts)

The entry point for all route classification is **[`src/server/authz/classify.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/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:

```typescript
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`](https://github.com/diegosouzapw/OmniRoute/blob/main/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/onboarding`** → **PUBLIC** with reason `setup_wizard`
- **`/connect…`** → **PUBLIC** with reason `public_connect_page`
- **Any path beginning with `/dashboard`** → **MANAGEMENT** 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`](https://github.com/diegosouzapw/OmniRoute/blob/main/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`](https://github.com/diegosouzapw/OmniRoute/blob/main/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`](https://github.com/diegosouzapw/OmniRoute/blob/main/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:

```typescript
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`](https://github.com/diegosouzapw/OmniRoute/blob/main/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`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/server/authz/pipeline.ts).
- **Public API routes** are defined in [`src/shared/constants/publicApiRoutes.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/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`](https://github.com/diegosouzapw/OmniRoute/blob/main/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`](https://github.com/diegosouzapw/OmniRoute/blob/main/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.