If you have ever called an API from JavaScript and gotten a message like this in the console:
Access to fetch at 'https://api.example.com/data' from origin
'http://localhost:3000' has been blocked by CORS policy:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
...then you are dealing with a CORS error. This is one of the most confusing errors for beginner developers because the JavaScript code looks correct, yet the request keeps failing. This article explains what CORS is, why it appears, and — most importantly — where the correct fix belongs.
What Is CORS?
CORS (Cross-Origin Resource Sharing) is a browser security mechanism. By default, the browser forbids JavaScript on one origin (a combination of protocol + domain + port) from accessing resources on a different origin, unless the target server explicitly allows it via the Access-Control-Allow-Origin header.
Examples of origins considered different:
http://localhost:3000vshttp://localhost:8000(different port)http://site.comvshttps://site.com(different protocol)https://site.comvshttps://api.site.com(different subdomain)
The Biggest Misconception: CORS Is Not Fixed in JavaScript
This is the most important point. CORS cannot be fixed on the client side (fetch/Axios). Adding headers to your request will not help, because the rule is enforced by the browser based on the server's response. So the correct solution is to allow your origin on the API server — or use a proxy. Let's look at how, per platform.
Solution 1: Allow CORS in Laravel
Laravel already has a built-in CORS configuration in config/cors.php. To allow requests from your front-end:
// config/cors.php
return [
'paths' => ['api/*', 'sanctum/csrf-cookie'],
'allowed_methods' => ['*'],
'allowed_origins' => ['http://localhost:3000', 'https://app.yourdomain.com'],
'allowed_headers' => ['*'],
'supports_credentials' => true,
];
After changing this file, run php artisan config:clear. Avoid using '*' in allowed_origins when supports_credentials is true — that combination is rejected by the CORS spec.
Solution 2: Allow CORS in Native PHP
If your API is plain PHP (no framework), add the headers at the very top of the endpoint file:
<?php
header('Access-Control-Allow-Origin: https://yourdomain.com');
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
// Handle the preflight request (OPTIONS)
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
http_response_code(204);
exit;
}
Solution 3: Allow CORS in Node.js / Express
const cors = require('cors');
app.use(cors({
origin: 'http://localhost:3000',
credentials: true
}));
Understanding the "Preflight Request" (OPTIONS)
For certain requests (e.g. sending JSON with the Content-Type: application/json header, or PUT/DELETE methods), the browser first sends an OPTIONS request to "ask permission." If the server does not answer this OPTIONS request correctly, you will still hit a CORS error even though the main endpoint is already allowed. Make sure the server handles the OPTIONS method (see the PHP example above).
A Temporary Solution During Development: Proxy
If you cannot change the API server (for example, a third-party API), use a proxy in your development environment. Example in Vite (vite.config.js):
export default {
server: {
proxy: {
'/api': {
target: 'https://api.example.com',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
}
}
}
}
With this, the front-end calls /api/data (same-origin), and the dev server forwards it to the real API — so the browser does not block it.
Don't Do This
- Don't install a "disable CORS" browser extension as a production solution — it only masks the problem on your computer, not for your users.
- Don't add the
Access-Control-Allow-Originheader to your JavaScript request — that header belongs to the server's response.
Conclusion
CORS errors appear because the browser protects users from unauthorized cross-origin access. The correct solution is always on the server side: allow your front-end origin via the Access-Control-Allow-Origin header, and make sure the OPTIONS preflight request is handled. For third-party APIs you cannot change, use a proxy. Once you understand that CORS is a server-to-browser rule, this error becomes far easier to solve.