CORS (Cross-Origin Resource Sharing) Setup for API
CORS — browser mechanism allowing or denying web pages to make requests to another domain. Without proper setup, frontend on app.example.com cannot access API on api.example.com, even if both belong to you.
How It Works
For "simple" requests (GET, POST with certain headers) browser sends request and checks response headers. For "complex" (PUT, DELETE, custom headers) preflight OPTIONS request comes first:
OPTIONS /api/users HTTP/1.1
Origin: https://app.example.com
Access-Control-Request-Method: DELETE
Access-Control-Request-Headers: Authorization, Content-Type
Server must respond with permission:
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: Authorization, Content-Type
Access-Control-Max-Age: 86400
Nginx Setup
location /api/ {
if ($request_method = 'OPTIONS') {
add_header Access-Control-Allow-Origin $http_origin;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS";
add_header Access-Control-Allow-Headers "Authorization, Content-Type, X-Requested-With";
add_header Access-Control-Max-Age 86400;
return 204;
}
add_header Access-Control-Allow-Origin $http_origin always;
add_header Access-Control-Allow-Credentials true always;
proxy_pass http://backend;
}
Laravel Setup
// config/cors.php
return [
'paths' => ['api/*'],
'allowed_methods' => ['*'],
'allowed_origins' => ['https://app.example.com', 'https://admin.example.com'],
'allowed_headers' => ['Authorization', 'Content-Type', 'X-Requested-With'],
'exposed_headers' => ['X-Total-Count'],
'max_age' => 86400,
'supports_credentials' => true,
];
Package fruitcake/laravel-cors (built in Laravel 7+) handles everything automatically via middleware.
Credentials and Cookies
If API uses cookie sessions or transmits credentials:
- Server must return
Access-Control-Allow-Credentials: true -
Access-Control-Allow-Origincannot be*— only specific domain - Frontend must specify
credentials: 'include'in fetch orwithCredentials: truein Axios
Common Mistakes
-
Access-Control-Allow-Origin: *withcredentials: true— browser blocks - Dynamic
$http_originwithout whitelist verification — any site gets access - Missing CORS headers on error responses (4xx/5xx) — frontend won't see error body
Implementation Timeline
Basic CORS setup for typical project — 2–4 hours.







