HTTP

Header

Access-Control-Allow-Origin

Learn how Access-Control-Allow-Origin controls which origins can access resources in CORS. Covers wildcard, specific origin, and credential configurations.

2 min read intermediate Try in Playground

TL;DR: Controls which origins can access resources in cross-origin requests. Use specific origins for security or * for public APIs (but not with credentials).

What is Access-Control-Allow-Origin?

Access-Control-Allow-Origin is a CORS (Cross-Origin Resource Sharing) response header that tells browsers which origins are allowed to access a resource from a different domain. It’s the server’s way of saying “yes, this website can use my data” or “no, access denied.”

Without this header, browsers block cross-origin requests by default for security reasons.

How It Works

When a web page at https://myapp.com tries to fetch data from https://api.example.com, the browser checks if the API allows this cross-origin request:

1. Browser makes the request:

GET /data HTTP/1.1
Host: api.example.com
Origin: https://myapp.com
```text

**2. Server responds with CORS header:**

```http
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://myapp.com
Content-Type: application/json

{"message": "Hello from API!"}

3. Browser allows the response because the origin matches.

Common Values

Allow Specific Origin

Access-Control-Allow-Origin: https://myapp.com
```text

Only `https://myapp.com` can access this resource.

### Allow All Origins (Wildcard)

```http
Access-Control-Allow-Origin: *

Any website can access this resource. Use with caution - only for public APIs.

Allow Multiple Origins

You can’t list multiple origins in one header. Instead, the server must dynamically set the header based on the request’s Origin:

// Server logic example
const allowedOrigins = ['https://app1.com', 'https://app2.com']
const origin = request.headers.origin

if (allowedOrigins.includes(origin)) {
  response.setHeader('Access-Control-Allow-Origin', origin)
}
```text

## Security Considerations

**Never use wildcard (`*`) with credentials:**

```http
❌ Access-Control-Allow-Origin: *
   Access-Control-Allow-Credentials: true

Instead, specify exact origins:

✅ Access-Control-Allow-Origin: https://trusted-app.com
   Access-Control-Allow-Credentials: true
```text

## Real-World Examples

### Public API

```http
Access-Control-Allow-Origin: *

Weather APIs, public data feeds, CDNs.

Private API

Access-Control-Allow-Origin: https://mycompany.com
```text

Internal company APIs, user dashboards.

### Development

```http
Access-Control-Allow-Origin: http://localhost:3000

Local development servers.

Common Issues

Problem: CORS error in browser console Solution: Server must include the correct Access-Control-Allow-Origin header

Problem: Wildcard doesn’t work with credentials Solution: Use specific origins when Access-Control-Allow-Credentials: true

Dynamic Origin Validation

The Access-Control-Allow-Origin header can only contain a single origin value or the wildcard *. To allow multiple specific origins, the server must read the Origin request header and dynamically echo back the matching allowed origin. This is the standard pattern for APIs that serve multiple frontend applications.

The key implementation detail is to also set Vary: Origin whenever you dynamically set Access-Control-Allow-Origin. Without Vary: Origin, a shared cache might serve a response with Access-Control-Allow-Origin: https://app1.com to a request from https://app2.com, causing a CORS failure. The Vary header tells caches to store separate responses for each distinct Origin value.

Never reflect the Origin header back unconditionally without checking it against an allowlist. Reflecting any origin without validation effectively grants all origins access to your API, which is equivalent to using * but without the browser’s built-in protection against using wildcards with credentials.

In Practice

Express.js
const cors = require('cors')

// Allow a single origin
app.use(cors({ origin: 'https://app.example.com' }))

// Allow multiple origins dynamically
const ALLOWED = new Set(['https://app.example.com', 'https://admin.example.com'])
app.use(cors({
  origin(origin, cb) {
    if (!origin || ALLOWED.has(origin)) return cb(null, true)
    cb(new Error('Not allowed by CORS'))
  },
  credentials: true // Allow cookies/Authorization header
}))

// Manual header (no middleware)
app.use((req, res, next) => {
  const origin = req.headers.origin
  if (ALLOWED.has(origin)) {
    res.set('Access-Control-Allow-Origin', origin)
    res.set('Vary', 'Origin')
  }
  next()
})
Next.js App Router
// app/api/data/route.ts
const ALLOWED_ORIGIN = 'https://app.example.com'

export async function GET(request: Request) {
  const origin = request.headers.get('origin') ?? ''
  const headers: HeadersInit = {}
  if (origin === ALLOWED_ORIGIN) {
    headers['Access-Control-Allow-Origin'] = origin
    headers['Vary'] = 'Origin'
  }
  return Response.json({ data: [] }, { headers })
}

export async function OPTIONS() {
  return new Response(null, {
    status: 204,
    headers: {
      'Access-Control-Allow-Origin': ALLOWED_ORIGIN,
      'Access-Control-Allow-Methods': 'GET, POST',
      'Access-Control-Allow-Headers': 'Content-Type, Authorization',
      'Access-Control-Max-Age': '86400'
    }
  })
}
Django
# Install: pip install django-cors-headers
# settings.py
INSTALLED_APPS = [..., 'corsheaders']
MIDDLEWARE = ['corsheaders.middleware.CorsMiddleware', ...]

# Allow specific origins
CORS_ALLOWED_ORIGINS = [
    'https://app.example.com',
    'https://admin.example.com',
]

# Allow credentials (cookies, Authorization header)
CORS_ALLOW_CREDENTIALS = True

# Or allow all origins for public APIs (no credentials)
# CORS_ALLOW_ALL_ORIGINS = True

Frequently Asked Questions

What is Access-Control-Allow-Origin?

This CORS header specifies which origins can access the resource. The browser blocks responses if the requesting origin is not allowed. Use specific origins or * for public APIs.

Can I allow multiple origins?

The header only accepts one origin or *. To allow multiple specific origins, check the request Origin header and dynamically return the matching allowed origin.

What does Access-Control-Allow-Origin: * mean?

The wildcard * allows any origin to access the resource. Use it only for public APIs. It cannot be used with credentials (cookies, authorization headers).

Why is my CORS request failing?

Check that the response includes Access-Control-Allow-Origin matching your origin. For preflight requests, ensure OPTIONS returns proper CORS headers. Credentials require exact origin, not *.

Keep Learning