CORS (Cross-Origin Resource Sharing)#
Configure Cross-Origin Resource Sharing to allow your API to be accessed from different domains.
Quick Start#
Enable CORS for all origins (development only):
final app = DartExpress();
app.use(app.cors());
app.get('/api/data', (req, res) {
res.json({'message': 'CORS enabled!'});
});
Production Configuration#
Restrict origins in production:
app.use(app.cors(
allowedOrigins: [
'https://myapp.com',
'https://www.myapp.com',
],
allowedMethods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true,
));
Configuration Options#
Allow Specific Origins#
app.use(app.cors(
allowedOrigins: ['https://example.com'],
));
Allow All Origins (Development)#
app.use(app.cors(
allowedOrigins: ['*'], // Allow all
));
Allow Methods#
app.use(app.cors(
allowedMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
));
Allow Headers#
app.use(app.cors(
allowedHeaders: [
'Content-Type',
'Authorization',
'X-Custom-Header',
],
));
Credentials#
Allow cookies and authentication:
app.use(app.cors(
credentials: true,
allowedOrigins: ['https://myapp.com'], // Required when credentials: true
));
Preflight Requests#
CORS automatically handles OPTIONS preflight requests:
Client Server
| |
|-- OPTIONS /api/data --> |
| |
|<-- 204 No Content ----- | (with CORS headers)
| |
|-- POST /api/data -----> |
|<-- 200 OK ------------- |
Common Use Cases#
API for Web App#
app.use(app.cors(
allowedOrigins: [
'https://app.example.com',
'https://dashboard.example.com',
],
allowedMethods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true,
));
Public Read-Only API#
app.use(app.cors(
allowedOrigins: ['*'],
allowedMethods: ['GET'],
allowedHeaders: ['Content-Type'],
));
Development with localhost#
app.use(app.cors(
allowedOrigins: [
'http://localhost:3000',
'http://localhost:5173', // Vite
'http://localhost:8080',
],
));
Custom CORS Middleware#
For advanced scenarios, create custom CORS middleware:
Future<void> customCors(Request req, Response res, NextFunction next) async {
final origin = req.headers['origin'];
// Dynamic origin check
if (origin != null && origin.endsWith('.example.com')) {
res.setHeader('Access-Control-Allow-Origin', origin);
res.setHeader('Access-Control-Allow-Credentials', 'true');
}
// Handle preflight
if (req.method == 'OPTIONS') {
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
return res.status(204).send();
}
await next();
}
app.use(customCors);
Security Best Practices#
Never use * with credentials#
❌ Insecure:
app.use(app.cors(
allowedOrigins: ['*'],
credentials: true, // SECURITY RISK!
));
✅ Secure:
app.use(app.cors(
allowedOrigins: ['https://myapp.com'],
credentials: true,
));
Validate origins carefully#
final allowedOrigins = [
'https://myapp.com',
'https://www.myapp.com',
// Add staging/dev as needed
];
app.use(app.cors(
allowedOrigins: allowedOrigins,
));
Limit methods and headers#
Only allow what you need:
app.use(app.cors(
allowedMethods: ['GET', 'POST'], // Not PUT/DELETE if unused
allowedHeaders: ['Content-Type'], // Minimal headers
));
Testing CORS#
With curl#
curl -H "Origin: https://example.com" \
-H "Access-Control-Request-Method: POST" \
-H "Access-Control-Request-Headers: Content-Type" \
-X OPTIONS \
http://localhost:3000/api/data
With JavaScript#
fetch('http://localhost:3000/api/data', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
credentials: 'include', // For cookies
body: JSON.stringify({data: 'test'}),
});
Common Errors#
"No 'Access-Control-Allow-Origin' header"#
Cause: CORS not enabled or origin not allowed
Solution: Add CORS middleware:
app.use(app.cors(
allowedOrigins: ['https://yourapp.com'],
));
"Credential is not supported if wildcard"#
Cause: Using * with credentials: true
Solution: Specify exact origins:
app.use(app.cors(
allowedOrigins: ['https://yourapp.com'], // Not '*'
credentials: true,
));
Next Steps#
- Rate Limiting - Protect against abuse
- Sessions - Manage authenticated users
- Best Practices - Security guidelines