Match Origins with Regex Patterns

Use regex patterns to validate CORS origins dynamically. Handle wildcard subdomains, Vercel preview URLs, and dynamic staging environments.

Common Issues

Detailed Explanation

Regex-Based Origin Validation

When you have many subdomains or dynamically generated origins (like Vercel preview deployments), maintaining a static allowlist becomes impractical. Regex matching lets you validate origins against a pattern.

Common Patterns

Pattern Matches
^https://.*\.example\.com$ Any subdomain of example.com
^https://.*\.vercel\.app$ Vercel preview deployments
`^https://(app admin
^https?://localhost(:\d+)?$ localhost on any port

Express.js Implementation

const corsOptions = {
  origin: (origin, callback) => {
    if (!origin) return callback(null, true); // Allow non-browser requests

    const patterns = [
      /^https:\/\/.*\.example\.com$/,
      /^https:\/\/.*\.vercel\.app$/,
    ];

    const isAllowed = patterns.some((pattern) => pattern.test(origin));
    if (isAllowed) {
      callback(null, true);
    } else {
      callback(new Error("Not allowed by CORS"));
    }
  },
  credentials: true,
};

Nginx Implementation

# Match subdomains of example.com
if ($http_origin ~* "^https://.*\.example\.com$") {
    set $cors_origin $http_origin;
}

# Match Vercel preview URLs
if ($http_origin ~* "^https://.*\.vercel\.app$") {
    set $cors_origin $http_origin;
}

add_header Access-Control-Allow-Origin $cors_origin always;
add_header Vary Origin always;

Security Warning

Be very careful with regex patterns. A poorly written regex can accidentally match malicious origins:

Pattern Vulnerability
example.com Matches evil-example.com
^https://example\.com Missing $ — matches example.com.evil.com
.*\.example\.com Missing ^ and protocol — could match http://

Always anchor both ends (^ and $) and include the protocol in your pattern.

Vercel Preview URLs

Vercel generates URLs like https://my-app-abc123.vercel.app. To support these:

const isAllowed = /^https:\/\/my-app-[a-z0-9]+\.vercel\.app$/.test(origin);

This is more secure than matching all .vercel.app domains, which would allow anyone's Vercel deployment.

Use Case

A team using Vercel for deployments needs CORS to work for both production (app.example.com) and preview URLs (my-app-abc123.vercel.app). A static allowlist cannot keep up with the constantly changing preview URLs.

Try It — CORS Header Builder

Open full tool