- Home
- HTTP Headers
- Access-Control-Allow-Origin
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.
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
Related Headers
- Vary - Cache different responses per origin
- Access-Control-Allow-Methods - Allowed HTTP methods
- Access-Control-Allow-Headers - Allowed request headers
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 = TrueFrequently 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 *.