Skip to content

CORS Multiple Origins — Supporting Several Domains Without Using Wildcards

DodaTech Updated 2026-06-28 4 min read

In this tutorial, you will learn about CORS Multiple Origins. We cover key concepts, practical examples, and best practices to help you master this topic.

CORS does not support listing multiple origins in a single Access-Control-Allow-Origin header. To support multiple origins, the server must dynamically set the header to the specific origin that matches the request Origin header.

What You'll Learn

  • How to implement dynamic origin resolution
  • Managing origin whitelists securely
  • Handling the Vary header for Caching

Why It Matters

Most production APIs serve multiple frontend applications: a main website, an admin dashboard, and perhaps a mobile web view. Each requires different CORS origins. DodaTech's API serves both the public website and the partner portal with a shared dynamic origin middleware.

flowchart TD
    A["Request arrives"] --> B["Read Origin header"]
    B --> C["Look up origin in whitelist"]
    C --> D{"Origin found?"}
    D -->|"Yes"| E["Set ACAO to matched origin"]
    D -->|"No"| F["Do not set ACAO"]
    E --> G["Set Vary: Origin"]
    G --> H["Return response"]
    F --> H
    style E fill:#86efac,stroke:#16a34a
    style F fill:#fecaca,stroke:#dc2626

Code Examples

# Flask dynamic origin whitelist
ALLOWED_ORIGINS = frozenset([
    'https://app.example.com',
    'https://admin.example.com',
    'https://dashboard.example.com',
    'https://partners.example.com'
])

@app.after_request
def dynamic_origin(response):
    origin = request.headers.get('Origin')
    if origin in ALLOWED_ORIGINS:
        response.headers['Access-Control-Allow-Origin'] = origin
        response.headers['Vary'] = 'Origin'
        if request.method == 'OPTIONS':
            response.headers['Access-Control-Allow-Methods'] = \
                'GET, POST, PUT, DELETE, OPTIONS'
            response.headers['Access-Control-Allow-Headers'] = \
                'Content-Type, Authorization'
    return response
// Node.js dynamic origin with Express
const allowedOrigins = [
  'https://app.example.com',
  'https://admin.example.com',
  /\.trusted-partner\.com$/
];

const corsOptions = {
  origin: function (origin, callback) {
    if (!origin) return callback(null, true);
    const allowed = allowedOrigins.some(pattern => {
      if (pattern instanceof RegExp) return pattern.test(origin);
      return pattern === origin;
    });
    if (allowed) {
      callback(null, origin);
    } else {
      callback(new Error(`Origin ${origin} not allowed`));
    }
  },
  credentials: true
};
app.use(cors(corsOptions));
# Test multiple origins
curl -I -H "Origin: https://app.example.com" \
  https://api.example.com/data | grep -i "access-control"

curl -I -H "Origin: https://admin.example.com" \
  https://api.example.com/data | grep -i "access-control"

curl -I -H "Origin: https://evil.com" \
  https://api.example.com/data | grep -i "access-control"
# No ACAO header for blocked origins

Common Mistakes

1. Returning ACAO with Multiple Origins Separated by Commas

ACAO only accepts a single value. Multiple origins must be handled dynamically.

2. Not Validating Origin Values

Always validate against a whitelist. Never echo the Origin header without validation.

3. Missing the Vary Header

Without Vary: Origin, CDN caches may serve responses meant for one origin to another.

4. Using Insecure Patterns

Regex patterns for origin validation must be precise to avoid matching malicious domains.

5. Hardcoding Origins in Multiple Places

Centralize the origin list in a configuration file or environment variable.

Practice Questions

  1. Why can't you list multiple origins in ACAO?
  2. How do you implement multi-origin CORS support?
  3. What is the purpose of the Vary: Origin header?
  4. How should you validate origins in a whitelist?
  5. Can you use regex patterns for origin matching?

Answers:

  1. The CORS spec only allows a single origin, *, or null.
  2. Read the Origin header, check against a whitelist, and set ACAO to that specific origin.
  3. It tells caches to cache separate responses for different origins.
  4. Compare against a whitelist of exact origins. Use exact matches when possible.
  5. Yes, but be extremely careful to avoid overly permissive patterns.

Challenge: Build a CORS origin management system with a database-backed whitelist, an admin API to add/remove origins, and a middleware that resolves origins dynamically. Include audit logging for all origin validation decisions.

FAQ

What is the performance impact of dynamic origin resolution?

Minimal. Origin validation is a string comparison or regex test that takes microseconds. The Vary header ensures correct caching behavior.

Can I use subdomain wildcards in the origin whitelist?

Yes, by implementing pattern matching server-side. For example, match *.example.com against the Origin header. The ACAO header still returns the exact origin.

How does dynamic origin affect server-side caching?

The Vary: Origin header ensures caches store separate copies for different origins. Without it, a cached response for origin A might be served to origin B.

Should I allow requests with no Origin header?

Only if your API is also accessed by non-browser clients like mobile apps or server-to-server integrations. The Origin header may be absent in these cases.

How many origins can I reasonably support?

There is no hard limit. Each origin requires a few bytes in the response. A whitelist of hundreds of origins is feasible but consider using patterns or a lookup service for scale.

Mini Project

Build a CORS origin dashboard: a web interface to manage allowed origins, view real-time origin validation logs, see which origins are most active, and test whether a given origin would be allowed. Include alerts when blocked origins attempt to access the API.

What's Next

Build a complete dynamic origin whitelisting system with database-backed configuration, then explore Express CORS middleware for framework-specific implementation.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro