What is CORS?
CORS (Cross-Origin Resource Sharing) is a security feature in web browsers that blocks requests made from one domain (origin) to another unless explicitly allowed by the server. It prevents malicious scripts from accessing data on a different origin.
How CORS Works
When a frontend (e.g., https://example.com
) makes an API request to a different backend (e.g., https://api.external.com
), the browser checks whether the backend allows requests from the frontend’s origin. If not, the request is blocked.
1. Why Does a CORS Issue Occur?
A CORS error occurs when:
- The external API does not allow requests from your origin.
- The API does not include the proper CORS headers.
- A preflight request (OPTIONS) fails.
- The browser blocks the request due to security policies.
Example CORS Error Message:
Access to fetch at 'https://api.external.com/data' from origin 'https://mywebsite.com'
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
2. Understanding CORS Headers
The server must include specific HTTP headers to allow cross-origin requests.
Header | Purpose |
---|---|
Access-Control-Allow-Origin | Specifies which origins are allowed (e.g., * or https://example.com ). |
Access-Control-Allow-Methods | Lists allowed HTTP methods (GET, POST, PUT, DELETE ). |
Access-Control-Allow-Headers | Specifies allowed headers (Content-Type, Authorization ). |
Access-Control-Allow-Credentials | Allows sending cookies and credentials. |
Example of a valid CORS response from the API server:
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
3. How to Fix a CORS Issue
A) Fixing CORS from the Backend
If you control the API server, add CORS headers in the response.
For Express.js (Node.js)
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors()); // Enables CORS for all routes
app.get('/data', (req, res) => {
res.json({ message: 'CORS enabled' });
});
app.listen(3000, () => console.log('Server running on port 3000'));
For Python (Flask)
from flask import Flask
from flask_cors import CORS
app = Flask(__name__)
CORS(app) # Enables CORS for all routes
@app.route('/data')
def data():
return {'message': 'CORS enabled'}
if __name__ == '__main__':
app.run(port=5000)
B) Using a Proxy Server
If you cannot modify the API server, use a proxy to add CORS headers.
1. Using a CORS Proxy
A free service like CORS Anywhere can help:
fetch('https://cors-anywhere.herokuapp.com/https://api.external.com/data')
However, free proxies may be slow or unreliable.
2. Setting Up Your Own Proxy (Node.js)
const express = require('express');
const request = require('request');
const cors = require('cors');
const app = express();
app.use(cors());
app.get('/proxy/:url', (req, res) => {
const url = decodeURIComponent(req.params.url);
request(url).pipe(res);
});
app.listen(4000, () => console.log('Proxy server running on port 4000'));
Now, call your proxy instead:
fetch('http://localhost:4000/proxy/https://api.external.com/data')
C) Configuring CORS in Nginx
If your backend runs on Nginx, add the following in the config:
location /api/ {
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type';
}
Restart Nginx:
sudo systemctl restart nginx
D) Handling Preflight Requests
For POST
, PUT
, or DELETE
requests, the browser first sends an OPTIONS request (preflight).
If your API does not handle it, add a response:
app.options('*', (req, res) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
res.sendStatus(200);
});
4. Workarounds if You Can’t Fix CORS on the Backend
- Use JSONP (for
GET
requests only)function fetchJSONP(url, callback) { const script = document.createElement('script'); script.src = `${url}?callback=${callback}`; document.body.appendChild(script); } fetchJSONP('https://api.external.com/data', 'handleData');
(Note: JSONP is outdated and not recommended.) - Disable CORS in the Browser (for testing) Run Chrome with CORS disabled:
chrome.exe --disable-web-security --user-data-dir="C:/ChromeDev"
(Not recommended for production use!) - Use a Browser Extension
- Install CORS Unblock or Moesif CORS.