CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-cors

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

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

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;

docs

index.md

tile.json