Match Origins with Regex Patterns
Use regex patterns to validate CORS origins dynamically. Handle wildcard subdomains, Vercel preview URLs, and dynamic staging environments.
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.