# How OmniRoute Implements CORS and Zod Validation for Secure API Routing

> OmniRoute centralizes CORS handling and uses Zod for type-safe API request validation. Secure your routes with this robust middleware system.

- Repository: [Diego Rodrigues de Sa e Souza/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- Tags: how-to-guide
- Published: 2026-08-30

---

**OmniRoute centralizes Cross-Origin Resource Sharing (CORS) handling through a pipeline-based middleware system and enforces type-safe request validation using Zod schemas across all API endpoints.**

OmniRoute is an open-source API routing layer designed to standardize provider interactions while maintaining strict security boundaries. This analysis examines how the diegosouzapw/OmniRoute repository implements CORS and Zod validation to create a consistent, secure request handling pipeline that applies uniformly across every route.

## CORS Implementation Architecture

OmniRoute treats CORS as a cross-cutting concern rather than per-route boilerplate, implementing it through a layered middleware approach that intercepts every request and response.

### Centralized Header Definitions

All standard CORS headers are defined as constants in [`src/shared/utils/cors.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/shared/utils/cors.ts). The `CORS_HEADERS` object provides a single source of truth for `Access-Control-Allow-Methods`, `Access-Control-Allow-Headers`, and other required fields, ensuring consistency across the application.

### Dynamic Origin Resolution

The system supports runtime-configurable allowed origins through the `corsOrigins` setting managed in [`src/lib/config/runtimeSettings.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/config/runtimeSettings.ts). When configuration changes, the `applyCorsOriginsSection` helper dynamically loads [`src/server/cors/origins.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/server/cors/origins.ts) to parse CSV-formatted origin strings into an allowed-origin set.

The `resolveAllowedOrigin` function in [`src/server/cors/origins.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/server/cors/origins.ts) validates the request's `Origin` header against this configured set before injecting appropriate response headers.

### Pipeline Middleware Integration

Every API route inherits CORS handling automatically through the authorization pipeline in [`src/server/authz/pipeline.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/server/authz/pipeline.ts). This pipeline imports `applyCorsHeaders` and invokes it at critical stages: pre-flight handling, success responses, error handling, and rate-limit rejections.

The `applyCorsHeaders` function accepts three parameters: the `response` object, the `request` object, and an optional `corsRelaxOrigin` boolean. When `corsRelaxOrigin` is true, the function supports internal tooling scenarios by bypassing strict origin validation while still injecting standard CORS headers.

## Zod Validation Patterns

OmniRoute leverages Zod for runtime type checking, ensuring that all incoming requests match expected schemas before business logic executes.

### Schema Organization

Central schema collections reside in `src/shared/validation/`, with domain-specific files including [`schemas/settings.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/schemas/settings.ts), [`schemas/provider.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/schemas/provider.ts), and [`schemas/routing.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/schemas/routing.ts). This organization allows routes to import shared validation logic or define inline schemas for endpoint-specific requirements.

Routes typically define schemas using standard Zod methods like `z.object()`, `z.string()`, and `z.number()`, then apply modifiers such as `.optional()` or `.passthrough()` depending on whether the endpoint needs to allow additional unknown properties.

### Runtime Validation Flow

Routes validate requests immediately upon entry before executing business logic. For example, the chat completion endpoint in `src/app/api/v1/providers/[provider]/chat/completions/route.ts` defines its body schema as:

```typescript
const routeBodySchema = z.object({ 
  model: z.string().optional() 
}).passthrough();

```

The schema's `safeParse` method detects malformed payloads immediately. If validation fails, the route returns a `400 Bad Request` response before any provider-specific processing occurs, preventing invalid data from reaching downstream services.

### Uniform Error Reporting

When Zod validation fails, routes call the shared `buildErrorBody` utility from the error handling module to generate sanitized JSON error responses. This ensures consistent error formatting—including standardized status codes and error messages—across the entire API surface, regardless of which specific schema triggered the validation exception.

## Practical Implementation Examples

To implement CORS in a custom route, import the utilities from the shared modules and apply headers before returning the response:

```typescript
import { CORS_HEADERS } from "@/shared/utils/cors";
import { applyCorsHeaders } from "@/server/cors/origins";

export async function GET(request: Request) {
  const response = new Response(
    JSON.stringify({ status: "healthy" }), 
    {
      headers: { "Content-Type": "application/json" },
    }
  );
  
  return applyCorsHeaders(response, request);
}

```

For POST endpoints requiring strict payload validation, use Zod's `safeParse` pattern with the error builder:

```typescript
import { z } from "zod";
import { buildErrorBody } from "@/shared/utils/error";

const payloadSchema = z.object({
  name: z.string().min(1),
  age: z.number().int().positive(),
  provider: z.string().optional(),
});

export async function POST(request: Request) {
  const body = await request.json();
  const result = payloadSchema.safeParse(body);
  
  if (!result.success) {
    return new Response(
      buildErrorBody(400, "Invalid payload", result.error),
      { 
        status: 400,
        headers: { "Content-Type": "application/json" }
      }
    );
  }
  
  const validatedData = result.data;
  // Process validated data...
}

```

## Summary

- **Centralized CORS handling**: All CORS logic lives in [`src/server/cors/origins.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/server/cors/origins.ts) and [`src/shared/utils/cors.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/shared/utils/cors.ts), with automatic application through [`src/server/authz/pipeline.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/server/authz/pipeline.ts) ensuring no route requires manual header management.
- **Runtime origin configuration**: The `corsOrigins` setting in [`src/lib/config/runtimeSettings.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/config/runtimeSettings.ts) allows dynamic updates to allowed origins without code changes, parsed by `applyCorsOriginsSection`.
- **Type-safe validation**: Zod schemas in `src/shared/validation/` provide compile-time and runtime type checking, with route-specific schemas often using `.passthrough()` for flexible provider APIs.
- **Consistent error responses**: The `buildErrorBody` utility standardizes validation error formatting, automatically invoked when `safeParse` detects schema violations.
- **Pipeline integration**: CORS headers are injected via `applyCorsHeaders` at every pipeline stage, including error paths and rate-limit responses, ensuring cross-origin policies persist even during failures.

## Frequently Asked Questions

### How does OmniRoute handle preflight OPTIONS requests?

OmniRoute handles OPTIONS requests through the standard `applyCorsHeaders` function called within the authorization pipeline. When a preflight request arrives at [`src/server/authz/pipeline.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/server/authz/pipeline.ts), the pipeline detects the method and returns an early response with appropriate `Access-Control-Allow-Methods` and `Access-Control-Allow-Headers` headers derived from the `CORS_HEADERS` constant, without executing downstream business logic.

### Can I customize CORS origins without restarting the server?

Yes. The `corsOrigins` setting in [`src/lib/config/runtimeSettings.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/config/runtimeSettings.ts) supports runtime updates. When administrators modify this configuration, the `applyCorsOriginsSection` function reparses the CSV-formatted origin list in [`src/server/cors/origins.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/server/cors/origins.ts), updating the allowed-origin set immediately. The `resolveAllowedOrigin` function uses this updated set for all subsequent requests without requiring a server restart.

### What happens when Zod validation fails in OmniRoute?

When a schema's `safeParse` method returns a failure result, the route immediately constructs a 400 Bad Request response using `buildErrorBody`, passing the Zod error object for detailed but sanitized error messages. This prevents invalid data from reaching provider APIs and ensures clients receive consistent JSON error structures regardless of which endpoint triggered the validation.

### Where should I define custom Zod schemas for new routes?

Define shared schemas in `src/shared/validation/` following the existing pattern of domain-specific files like [`schemas/provider.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/schemas/provider.ts). For endpoint-specific validation that won't be reused, define the schema inline within the route file, as demonstrated in `src/app/api/v1/providers/[provider]/chat/completions/route.ts`. Always import the `z` object from the Zod package and use `safeParse` rather than `parse` to maintain control over error handling.