Dwex Logo

CORS

Configure Cross-Origin Resource Sharing

CORS

Learn how to configure CORS (Cross-Origin Resource Sharing) in your Dwex applications to allow your API to be accessed from different domains.

Overview

Dwex provides a built-in corsMiddleware function that handles CORS headers and preflight requests. The middleware is highly configurable and supports various use cases from simple open access to complex origin validation.

Basic Usage

Import and use the corsMiddleware function:

import { DwexFactory, corsMiddleware } from "@dwex/core";
import { AppModule } from "./app.module";

const app = await DwexFactory.create(AppModule);

// Allow all origins (useful for development)
app.use(corsMiddleware());

await app.listen(9929);

Configuration Options

Single Origin

Allow requests from a specific origin:

app.use(corsMiddleware({
	origin: "https://example.com",
	credentials: true,
}));

Multiple Origins

Allow requests from multiple origins:

app.use(corsMiddleware({
	origin: ["https://example.com", "https://app.example.com"],
	credentials: true,
}));

Dynamic Origin Validation

Use a function to dynamically validate origins:

app.use(corsMiddleware({
	origin: (origin) => {
		// Allow all subdomains of example.com
		return origin.endsWith(".example.com");
	},
	credentials: true,
}));

Custom Methods and Headers

Configure allowed methods and headers:

app.use(corsMiddleware({
	origin: "https://example.com",
	methods: ["GET", "POST", "PUT", "DELETE"],
	allowedHeaders: ["Content-Type", "Authorization", "X-Custom-Header"],
	exposedHeaders: ["X-Response-Id"],
	credentials: true,
	maxAge: 86400, // 24 hours
}));

Configuration Reference

OptionTypeDefaultDescription
originstring | string[] | ((origin: string) => boolean)"*"Allowed origins. Can be a string, array of strings, or validation function
methodsstring | string[]["GET", "HEAD", "PUT", "PATCH", "POST", "DELETE"]Allowed HTTP methods
allowedHeadersstring | string[]undefinedAllowed request headers. If not set, reflects the request's Access-Control-Request-Headers
exposedHeadersstring | string[]undefinedHeaders exposed to the client
credentialsbooleanfalseWhether to allow credentials (cookies, authorization headers)
maxAgenumberundefinedHow long (in seconds) the results of a preflight request can be cached
preflightContinuebooleanfalsePass the CORS preflight response to the next handler
optionsSuccessStatusnumber204Status code for successful OPTIONS requests

Examples

Development Setup

For local development, allow all origins:

const app = await DwexFactory.create(AppModule);

app.use(corsMiddleware({
	origin: "*",
	credentials: false,
}));

await app.listen(9929);

Production Setup

For production, restrict to specific origins:

const app = await DwexFactory.create(AppModule);

app.use(corsMiddleware({
	origin: ["https://example.com", "https://www.example.com"],
	credentials: true,
	methods: ["GET", "POST", "PUT", "DELETE"],
	allowedHeaders: ["Content-Type", "Authorization"],
	maxAge: 3600,
}));

await app.listen(9929);

Advanced: Environment-Based Configuration

Configure CORS based on environment:

const app = await DwexFactory.create(AppModule);

const isDevelopment = Bun.env.NODE_ENV === "development";

app.use(corsMiddleware({
	origin: isDevelopment
		? "*"
		: ["https://example.com", "https://www.example.com"],
	credentials: !isDevelopment,
	methods: ["GET", "POST", "PUT", "DELETE", "PATCH"],
}));

await app.listen(9929);

Preflight Requests

The middleware automatically handles preflight OPTIONS requests. When a browser sends a preflight request:

  1. The middleware checks if the origin is allowed
  2. Sets the appropriate CORS headers
  3. Responds with the configured optionsSuccessStatus (default 204)
  4. Ends the request unless preflightContinue is true

Security Considerations

Credentials and Wildcards

When using credentials: true, you cannot use a wildcard ("*") for the origin. You must specify exact origins:

// This will not work properly with credentials
app.use(corsMiddleware({
	origin: "*",
	credentials: true,
}));

// Use specific origins instead
app.use(corsMiddleware({
	origin: ["https://example.com"],
	credentials: true,
}));

Origin Validation

Always validate origins in production. Avoid using "*" in production environments:

// Development only
app.use(corsMiddleware({
	origin: "*",
}));

// Production - use specific origins or validation function
app.use(corsMiddleware({
	origin: (origin) => {
		const allowedDomains = [".example.com", ".app.example.com"];
		return allowedDomains.some(domain => origin.endsWith(domain));
	},
	credentials: true,
}));