HTTP Access Control (CORS)
Last Updated :
18 Feb, 2025
Modern web applications often need to fetch data from different domains, known as a cross-origin request. For example, a site hosted on 'example.com' might need resources from 'api.example.com'. However, browsers enforce the Same-Origin Policy (SOP), which blocks requests to different domains for security, preventing issues like cross-site request forgery (CSRF).
To allow safe communication between different domains, Cross-Origin Resource Sharing (CORS) is used. CORS enables developers to specify which domains are permitted to access resources, bypassing SOP restrictions when necessary.
What is CORS?
CORS (Cross-Origin Resource Sharing) is a security feature implemented by web browsers that allows or denies requests for resources from one domain to be made from a different domain. It is a mechanism that allows web servers to specify which domains are permitted to access the resources they serve.
In simple terms, CORS defines how a browser should behave when making requests for resources (e.g., API calls, images, scripts) to a server from a different origin. Without CORS, browsers block these cross-origin requests to maintain security.
Why is CORS Important?
Without CORS, a malicious website could make API calls on behalf of a user and steal their sensitive data (e.g., making requests to a banking API from an unauthorized site). CORS helps prevent such attacks by restricting cross-origin requests unless explicitly allowed by the server.
Example of a CORS Issue
Imagine your front end is hosted at:
https://frontend-example.com
And your API is hosted at:
https://api-example.com
If your frontend tries to fetch data from the API using:
fetch('https://api-example.com/data')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.log(error));
The browser blocks the request and throws a CORS error unless the API explicitly allows it.
What Requests Use CORS?
HTTP requests to another origin (domain, protocol, or port) use CORS. These types of requests include:
- Simple requests: These are requests via GET, POST, or HEAD methods. Credentials included are things like HTTP headers and or cookies but not custom headers. The browser will handle simple requests automatically without a preflight check.
- Non-simple requests: However, requests that use methods other than GET, POST, or HEAD (ie. PUT, DELETE), has custom headers, or sent credentials (eg cookies or tokens), all need to be checked further. Preworks by checking with the server with another request: the OPTIONS method.
- Cross-origin resource requests with credentials: The server must explicitly allow an application when an application must send or receive cookies, authentication headers, or other credentials from a different origin.
How CORS Works?
To allow cross-origin requests, the server needs to send CORS headers in the response.
- Browser sends request: The browser attaches an Origin header to a request when you make a request from one origin to another.
Example (http):
GET /api/data HTTP/1.1
Origin: https://frontend.com
- Server evaluates request: The server checks this Origin header on the request and allows or denies on the set of CORS policies.
- Server response: The server responds with appropriate CORS headers, e. g. Access-Control-Allow-Origin, if the server allows the origin requests, otherwise it denies the origin by returning an error (403 for example) response.
- Example (HTTP): HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://frontend.com
- Browser enforcement: If the CORS headers are legal, the browser will accept request & display result. A request is blocked (browser blocked with 403 error) and the resource isn't reachable if the headers are missing or if they’re not correct.
Header | Description |
---|
Access-Control-Allow-Origin | Specifies which domains can access the resource. Example: * (allows all origins) or https://example.com |
---|
Access-Control-Allow-Methods | Defines allowed HTTP methods (GET, POST, PUT, DELETE, OPTIONS). |
---|
Access-Control-Allow-Headers | Specifies which headers the client can send. |
---|
Access-Control-Allow-Credentials | Allows credentials like cookies and authentication tokens. |
---|
Access-Control-Allow-Origin (ACAO) HTTP Response Header
Without setting the Access-Control-Allow-Origin header, then any origin will be allowed to access the resource. This header can either:
- Specify a single domain: It lets only the given domain access the resource. Example (http):
Access-Control-Allow-Origin: https://frontend.com
- Use a wildcard (*): Any domain is then allowed to access the resource. In a way, this is convenient, but also insecure, if we don't use it properly.
Access-Control-Allow-Origin: *
It is not a good idea to use wildcard when the sensitive data or credentials are used.
Access-Control-Allow-Origin (ACAO) HTTP Request Header
A cross origin request includes the Origin header when a web browser sends a request. It will tell the server from which domain the request came from. According to which information it chooses to allow or deny access to this resource.
Example Request (http):
GET /api/data HTTP/1.1
Origin: https://frontend.com
Implementing Simple CORS
CORS is not too difficult to implement for simple GET or POST requests.
Now let us understand with the example.
Installation: First you need to install cors in your application.
npm install express cors
HTML
<!-- index.html -->
<html>
<head></head>
<body>
<h1>Check the Browser Console for Output</h1>
<script>
// Make a fetch request to the API
fetch('http://localhost:3000/data')
.then(response => response.json()) // Parse JSON response
.then(data => console.log(data)) // Log the data to console
.catch(error => console.log('Error:', error)); // Catch any error
</script>
</body>
</html>
JavaScript
// app.js
const express = require('express');
const cors = require('cors'); // Import the cors package
const app = express();
// Enable CORS for all origins (you can restrict it to specific domains later)
app.use(cors());
// Example route to get data
app.get('/data', (req, res) => {
res.json({
message: 'CORS is enabled for all origins!',
data: [1, 2, 3, 4, 5]
});
});
// Start the server
app.listen(3000, () => {
console.log('Server running on http://localhost:3000');
});
Now, if we will comment out the app.use(cors()), then it will throw the error.
Output
CORS ErrorWhen we use the app.use(cors())
HTTP Access Control (CORS)In this example
- app.use(cors()) allows all origins (or specific ones) to make requests to the server.
- /data: Sends a JSON response to the client.
- You can configure other routes as needed for your API.
- Use app.listen(3000) to start the server on http://localhost:3000, and handle incoming requests.
Handling Preflight Requests
Some requests (e.g., PUT, DELETE, requests with custom headers) trigger a preflight request before the actual request.
What is a Preflight Request?
A preflight request is an OPTIONS request sent by the browser to check if CORS is allowed before making the actual request.
Example of a Preflight Request
OPTIONS /api/data HTTP/1.1
Origin: https://frontend.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Content-Type
The server responds with (http):
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://frontend.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Content-Type
Handling Preflight in Express.js
app.options('/data', cors()); // Enable CORS for preflight requests
Common CORS Errors and Fixes
Error | Cause | Solution |
---|
CORS policy: No 'Access-Control-Allow-Origin' header | Server did not send CORS headers | Add Access-Control-Allow-Origin in response headers |
---|
CORS policy: Method not allowed | Server does not allow the HTTP method | Add Access-Control-Allow-Methods in headers |
---|
CORS policy: Credential not allowed | Request uses credentials, but server does not allow them | Set Access-Control-Allow-Credentials: true |
---|
Does CORS Protect Against CSRF?
CORS is not intended to circumvent Cross Site Request Forgery (CSRF) attacks. CSRF attacks are attacks where a user’s authenticated session is exploited to force them to make another unwanted request to another website. Cross domain restrictions (CORS) only apply to the interactions between domains, so CSRF is not prevented.
In order to mitigate CSRF you should further increase your security measures such as CSRF tokens or check if the request’s Origin and Referer headers are set.
Vulnerabilities in CORS
Incorrect CORS configurations can put your application in danger of threats. Here are some common vulnerabilities:
- Wildcard in Access-Control-Allow-Origin: However, using the * allows all the origins to access to the sensitive resources.
- Misconfigured credentials: But allowing credentials (cookies, authentication headers) with wildcard origins opens a gaping security hole.
- Improper use of preflight requests: Sometimes if the server handles preflight requests incorrectly it can grant restricted resources to unauthorized domains.
Best Practices for Managing CORS
- Restrict Origins: Avoid using *, instead allow specific trusted domains.
- Allow Only Necessary Methods: Limit Access-Control-Allow-Methods to only required HTTP methods.
- Use Middleware: In Express, use the Cors package instead of manually setting headers.
- Secure API Credentials: Avoid sending sensitive data in public CORS requests.
- Enable Preflight Requests: Handle OPTIONS requests properly to avoid request failures.
Similar Reads
HTTP headers | cache-control
The Cache-Control header is a general header, that specifies the caching policies of server responses as well as client requests. Basically, it gives information about the manner in which a particular resource is cached, location of the cached resource, and its maximum age attained before getting ex
3 min read
HTTP headers | Access-Control-Max-Age
The Access-Control-Max-Age HTTP header is a response header that gives the time for which results of a CORS preflight request that checks to see if the CORS protocol is understood and a server is aware using specific methods and headers, can be cached. The CORS preflight request contained in the Acc
1 min read
HTTP headers | Access-Control-Expose-Headers
The HTTP Access-Control-Expose-Headers header is a response header that is used to expose the headers that have been mentioned in it. By default 6 response headers are already exposed which are known as CORS-safelisted response headers. They are namely- Cache-Control, Content-Language, Content-Type,
1 min read
HTTP headers | Access-Control-Allow-Origin
The Access-Control-Allow-Origin is a response header that is used to indicates whether the response can be shared with requesting code from the given origin. Syntax: Access-Control-Allow-Origin: * | <origin> | null Directives: Access-Control-Allow-Origin accepts there types of directives menti
2 min read
HTTP headers | Access-Control-Allow-Methods
The Access-Control-Allow-Methods header is a Cross-Origin Resource Sharing(CORS) response-type header. It is used to indicate which HTTP methods are permitted while accessing the resources in response to the cross-origin requests. Syntax: Access-Control-Allow-Methods: <method>, <method>,
1 min read
HTTP headers | Access-Control-Allow-Headers.
The HTTP Access-Control-Allow-Headers header is a response-type header that is used to indicate the HTTP headers. It can be used during a request and is used in response to a CORS preflight request, that checks to see if the CORS protocol is understood and a server is aware using specific methods an
1 min read
HTTP headers | Access-Control-Allow-Credentials
The HTTP Access-Control-Allow-Credentials is a Response header. The Access-Control-Allow-Credentials header is used to tell the browsers to expose the response to front-end JavaScript code when the request's credentials mode Request.credentials is "include". Remember one thing when the Request.crede
2 min read
HTTP headers | Access-Control-Request-Method
The HTTP headers Access-Control-Request-Method is a request type header which has been used to inform the server that which HTTP method will be used when the actual request is made. Syntax: Access-Control-Request-Method: <method> Directives: This header accept a single directive which is menti
1 min read
HTTP headers | Access-Control-Request-Headers
Access-Control-Request-Headers is a request-type header used by browsers that contains information about the different HTTP headers that will be sent by the client in the ensuing request. Whenever a client initiates a request to a server, the browser checks if the request needs a CORS preflight or n
2 min read
How to Prevent Broken Access Control?
Access control is a security mechanism to put restrictions on the accessibilities of the resources and decide who or what can view or use the resources of a company. This is checked after authentication, and what authorized users are allowed to do. It is not an easy task to do, any failure while che
5 min read