or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/npm-cors

Node.js CORS middleware for Connect and Express applications with comprehensive configuration options

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/cors@2.8.x

To install, run

npx @tessl/cli install tessl/npm-cors@2.8.0

index.mddocs/

CORS

CORS is a Node.js middleware package for providing Cross-Origin Resource Sharing (CORS) functionality to Connect and Express applications. It enables web applications to handle cross-origin requests securely with comprehensive configuration options including origin validation, HTTP methods configuration, credential handling, and custom header management.

Package Information

  • Package Name: cors
  • Package Type: npm
  • Language: JavaScript
  • Installation: npm install cors

Core Imports

const cors = require('cors');

ES6 modules:

import cors from 'cors';

Basic Usage

const express = require('express');
const cors = require('cors');
const app = express();

// Enable CORS for all routes with default options
app.use(cors());

// Enable CORS for a single route
app.get('/api/data', cors(), (req, res) => {
  res.json({ message: 'This is CORS-enabled' });
});

// Configure CORS with custom options
const corsOptions = {
  origin: 'https://example.com',
  methods: ['GET', 'POST'],
  credentials: true
};

app.use(cors(corsOptions));

Architecture

CORS is built around several key components that handle different aspects of cross-origin request processing:

  • Middleware Factory: The main export creates Express/Connect middleware with static or dynamic configuration
  • Origin Validation Engine: Handles complex origin validation logic including arrays, RegExp patterns, and custom functions
  • Header Configuration System: Manages CORS headers for both preflight and actual requests with automatic reflection
  • Request Type Detection: Differentiates between simple requests and preflight OPTIONS requests
  • Automatic Vary Management: Adds appropriate Vary headers when origin or header reflection is used

Capabilities

CORS Middleware Factory

Creates Express/Connect middleware that handles CORS headers for both preflight and actual requests.

/**
 * Creates CORS middleware with optional configuration
 * @param {Object|Function} [options] - Static configuration object or dynamic options callback
 * @returns {Function} Express/Connect middleware function (req, res, next) => void
 */
function cors(options);

Static Configuration Options

Configure CORS behavior with a static options object.

interface CorsOptions {
  /** Configures Access-Control-Allow-Origin header */
  origin?: string | boolean | RegExp | Array<string | RegExp> | OriginCallback;
  /** Configures Access-Control-Allow-Methods header (arrays are joined with commas) */
  methods?: string | string[];
  /** Configures Access-Control-Allow-Headers header (arrays are joined with commas) */
  allowedHeaders?: string | string[];
  /** Alias for allowedHeaders */
  headers?: string | string[];
  /** Configures Access-Control-Expose-Headers header (arrays are joined with commas) */
  exposedHeaders?: string | string[];
  /** Configures Access-Control-Allow-Credentials header */
  credentials?: boolean;
  /** Configures Access-Control-Max-Age header (converted to string if number) */
  maxAge?: number | string;
  /** Pass preflight response to next handler instead of ending */
  preflightContinue?: boolean;
  /** Status code for successful OPTIONS requests */
  optionsSuccessStatus?: number;
}

Usage Examples:

// Allow specific origin
const corsOptions = {
  origin: 'https://example.com'
};
app.use(cors(corsOptions));

// Allow multiple origins using array
const corsOptions = {
  origin: ['https://example1.com', 'https://example2.com']
};
app.use(cors(corsOptions));

// Allow origins matching regex pattern
const corsOptions = {
  origin: /\.example\.com$/
};
app.use(cors(corsOptions));

// Configure methods and headers (arrays converted to comma-separated strings)
const corsOptions = {
  origin: true,
  methods: ['GET', 'POST', 'PUT', 'DELETE'], // Becomes 'GET,POST,PUT,DELETE'
  allowedHeaders: ['Content-Type', 'Authorization'], // Becomes 'Content-Type,Authorization'
  credentials: true,
  maxAge: 86400 // Converted to string '86400'
};
app.use(cors(corsOptions));

// Using headers alias instead of allowedHeaders
const corsOptions = {
  origin: true,
  headers: ['Content-Type', 'X-Custom-Header'] // Same as allowedHeaders
};
app.use(cors(corsOptions));

// Legacy browser compatibility
const corsOptions = {
  optionsSuccessStatus: 200 // Some legacy browsers choke on 204
};
app.use(cors(corsOptions));

Dynamic Origin Validation

Use a callback function for custom origin validation logic.

/**
 * Callback function for custom origin validation
 * @param {string} origin - Request origin from Origin header
 * @param {Function} callback - Callback function (err, allowedOrigin) => void
 *   - err: Error object or null
 *   - allowedOrigin: The origin value to use (string, boolean, etc.)
 */
type OriginCallback = (origin: string, callback: (err: Error | null, allowedOrigin: any) => void) => void;

Usage Examples:

// Whitelist specific origins
const whitelist = ['https://example1.com', 'https://example2.com'];
const corsOptions = {
  origin: function (origin, callback) {
    if (whitelist.indexOf(origin) !== -1 || !origin) {
      callback(null, origin); // Return the origin value, not boolean
    } else {
      callback(new Error('Not allowed by CORS'));
    }
  }
};
app.use(cors(corsOptions));

// Dynamic origin validation allowing/blocking
const corsOptions = {
  origin: function (origin, callback) {
    if (isAllowedOrigin(origin)) {
      callback(null, true); // true reflects the request origin
    } else {
      callback(null, false); // false disables CORS
    }
  }
};
app.use(cors(corsOptions));

// Custom origin transformation
const corsOptions = {
  origin: function (origin, callback) {
    // Transform origin or use custom logic
    const allowedOrigin = transformOrigin(origin);
    callback(null, allowedOrigin); // Can return string, boolean, etc.
  }
};
app.use(cors(corsOptions));

Dynamic Options Configuration

Use a callback function to determine CORS options dynamically per request.

/**
 * Callback function for dynamic CORS options per request
 * @param {Object} req - Express/Connect request object
 * @param {Function} callback - Callback function (err, options) => void
 */
type OptionsCallback = (req: any, callback: (err: Error | null, options: CorsOptions) => void) => void;

Usage Examples:

// Dynamic options based on request properties
const corsOptionsDelegate = function (req, callback) {
  let corsOptions;
  
  if (req.header('User-Agent') && req.header('User-Agent').includes('MyTrustedApp')) {
    corsOptions = { origin: true }; // Enable CORS for trusted apps
  } else {
    corsOptions = { origin: false }; // Disable CORS for others
  }
  
  callback(null, corsOptions);
};

app.use(cors(corsOptionsDelegate));

// Route-specific dynamic options
const corsOptionsDelegate = function (req, callback) {
  const corsOptions = {
    origin: req.path.startsWith('/api/public') ? true : 'https://trusted-domain.com',
    credentials: req.path.startsWith('/api/auth')
  };
  
  callback(null, corsOptions);
};

app.use(cors(corsOptionsDelegate));

Pre-flight Request Handling

Enable CORS pre-flight for complex requests that require an initial OPTIONS request.

Usage Examples:

// Enable pre-flight for a specific route
app.options('/api/data', cors()); // Enable pre-flight
app.delete('/api/data', cors(), (req, res) => {
  // DELETE request handler
});

// Enable pre-flight for all routes
app.options('*', cors()); // Include before other routes

// Continue processing after pre-flight
const corsOptions = {
  preflightContinue: true,
  optionsSuccessStatus: 200
};

app.options('/api/data', cors(corsOptions), (req, res) => {
  // Additional pre-flight logic
  res.sendStatus(200);
});

Configuration Defaults

const defaultOptions = {
  origin: '*',
  methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
  preflightContinue: false,
  optionsSuccessStatus: 204
};

Error Handling

CORS errors are passed to Express error handling middleware. Understanding error flow is important for proper CORS configuration:

// Origin callback errors - passed to Express error handler
const corsOptions = {
  origin: function (origin, callback) {
    if (!isValidOrigin(origin)) {
      callback(new Error('Not allowed by CORS')); // Triggers error middleware
    } else {
      callback(null, origin); // Return allowed origin
    }
  }
};

// Options callback errors - also passed to Express error handler
const corsOptionsDelegate = function (req, callback) {
  validateRequest(req)
    .then(options => callback(null, options))
    .catch(err => callback(err)); // Error passed to Express error handler
};

// Error handling middleware
app.use((err, req, res, next) => {
  if (err.message === 'Not allowed by CORS') {
    res.status(403).json({ error: 'CORS policy violation' });
  } else {
    next(err);
  }
});

// Important: Returning false vs throwing error
const corsOptions = {
  origin: function (origin, callback) {
    if (!isValidOrigin(origin)) {
      // Option 1: Return false to disable CORS (no error thrown)
      callback(null, false);
      
      // Option 2: Throw error to trigger error middleware
      // callback(new Error('Not allowed by CORS'));
    } else {
      callback(null, true);
    }
  }
};

Implementation Details

Automatic Vary Header Management

CORS automatically adds Vary headers when needed to ensure proper caching:

  • Vary: Origin: Added when origin is dynamic (function, array, or RegExp)
  • Vary: Access-Control-Request-Headers: Added when allowedHeaders/headers is not specified and headers are reflected from the request

Header Reflection Behavior

When allowedHeaders (or headers) is not specified:

  • CORS automatically reflects the request's Access-Control-Request-Headers
  • This allows maximum flexibility but may be less secure
  • A Vary: Access-Control-Request-Headers header is added

Array to String Conversion

Array values are automatically converted to comma-separated strings:

  • methods: ['GET', 'POST']'GET,POST'
  • allowedHeaders: ['Content-Type', 'Authorization']'Content-Type,Authorization'
  • exposedHeaders: ['X-Total-Count']'X-Total-Count'

Type Coercion

  • maxAge: Numbers are converted to strings (86400'86400')
  • methods, allowedHeaders, exposedHeaders: Arrays are joined with commas

Request Type Handling

Preflight Requests (OPTIONS):

  • Include all CORS headers: Origin, Methods, Headers, Max-Age, Credentials, Exposed-Headers
  • Response ends immediately unless preflightContinue: true

Simple Requests:

  • Include only: Origin, Credentials, Exposed-Headers
  • Processing continues to next middleware

Types

/**
 * CORS configuration options interface
 */
interface CorsOptions {
  /** 
   * Configures Access-Control-Allow-Origin CORS header
   * - string: Fixed origin
   * - boolean: true reflects request origin, false disables CORS
   * - RegExp: Pattern to test request origin
   * - Array: Array of valid origins (strings or regexps)
   * - Function: Custom origin validation logic
   */
  origin?: string | boolean | RegExp | Array<string | RegExp> | OriginCallback;
  
  /** 
   * Configures Access-Control-Allow-Methods CORS header
   * String: Comma-delimited methods
   * Array: Array of method strings
   */
  methods?: string | string[];
  
  /** 
   * Configures Access-Control-Allow-Headers CORS header
   * If not specified, reflects request's Access-Control-Request-Headers
   */
  allowedHeaders?: string | string[];
  
  /** Alias for allowedHeaders */
  headers?: string | string[];
  
  /** 
   * Configures Access-Control-Expose-Headers CORS header
   * Headers that clients can access
   */
  exposedHeaders?: string | string[];
  
  /** 
   * Configures Access-Control-Allow-Credentials CORS header
   * Set to true to pass the header
   */
  credentials?: boolean;
  
  /** 
   * Configures Access-Control-Max-Age CORS header
   * Cache duration for preflight requests in seconds
   */
  maxAge?: number | string;
  
  /** 
   * Pass CORS preflight response to next handler
   * Default: false (ends response immediately)
   */
  preflightContinue?: boolean;
  
  /** 
   * Status code for successful OPTIONS requests
   * Default: 204, set to 200 for legacy browser compatibility
   */
  optionsSuccessStatus?: number;
}

/**
 * Origin validation callback function
 */
type OriginCallback = (
  origin: string,
  callback: (err: Error | null, allowedOrigin: any) => void
) => void;

/**
 * Options callback function for dynamic configuration
 */
type OptionsCallback = (
  req: any,
  callback: (err: Error | null, options: CorsOptions) => void
) => void;

/**
 * Express/Connect middleware function signature
 */
type CorsMiddleware = (req: any, res: any, next: Function) => void;