An API serves as the backbone for the applications and makes it data rich, but sometimes life gets tough when you try to play with APIs that are not on the same origin where the app is located.
Due to security reasons, a request is not successfully fulfilled if the requested resource does not reside in the same origin from where the request has arrived. And this proves to be a bottleneck as the applications won’t be able to request/consume resources that are not on the same origin.
CORS – CROSS ORIGIN RESOURCE SHARING
To understand CORS and to make out the most of it safely, it is important to understand a bit how browsers work and its behaviour in such cases.
The Same Origin Policy
This Same Origin Policy restricts the browser from performing certain actions by scripts or documents based on their origin. The origin is domain name or the string component from the url before the first slash. There are some security reasons due to which browsers won’t allow you to access resources that are not from the same origin.
Scenarios when intentionally or unintentionally you break the Same Origin Policy :
- http://domain-a.com makes an
<img>
src request for http://domain-b.com/image.jpg - Sending an Ajax request to another server for the data.
A Step towards Cross-Origin Resource Sharing
CORS allows us to maintain separation of concern where the frontend (the look and feel, the HTML) can reside on a different server, and the backend that provides data to the former with API endpoints, is on another server.
Places where you see CORS in action:
- You are using a third party API e.g Facebook, google, twitter, etc.
- You are creating web app and utilising the API from another server.
For the case when you are using third party APIs you do not need to handle or worry much, as most of the things are being handled by these services. However, when building an API yourself, your server has to take care and identify and respond to requests accordingly.
IMPLEMENTING CORS
CORS is a set of response headers depending on which the browser decides whether to allow the request or not. Requests dealing with CORS can mainly be divided into two types
- Simple requests such as GET and POST. You don’t need to care, it works like a normal request.
- Preflight Requests with custom headers, custom response headers. More on preflight requests
Here you are trying to mess with the browser, which results the browser to send a preflight request to the server.
This request is to ask the server if the request with the headers and the data is permissible or not. Point to note here is that client does not need to worry about this, as this is being handled and sent by browser, but server has to take care of this request so that the CORS cycle can complete gracefully.
Preflight CORS Request
Let’s take an example where we want to get all the users with pagination, we have an access token that needs to be passed to the API server in Authorization header and the project’s backend has been hosted on http://projectbackend.com. When we create an ajax request for the mentioned case, browser will send an OPTIONS
request to the API server with the relevant headers.
You will be sending something like this
jQuery.ajax(
{
type: "POST",
url: "http://projectbackend.com/GetAllUsers",
headers : {
"Authorization" : "525045075934759",
"ItemsPerPage" : 10,
"PageNumber" : 1
}
},
This will result the browser to trigger a preflight request, which is basically a request with type OPTIONS
that is to check if the current request that holds the actual request header information is allowed or not. The server will respond to this OPTIONS
with variety of headers that tells the browser if the request is allowed or not, and exactly what is allowed for the request.
- Access-Control-Allow-Origin : Needs to be the origin of the request or * for allowing any application to use this as resource.
- Access-Control-Allow-Methods : Tells about the methods that are allowed while sending the actual request, that is a comma seperated values of methods such as
GET
,POST
,PUT
,DELETE
,PATCH
- Access-Control-Allow-Headers : Tells about the request headers that are allowed while requesting for the resource. This is also a comma seperated values of headers that can be allowed. Example :
authorisation
,x-client-token
. - Access-Control-Expose-Headers : This tells the browser headers that client can access. Server may be sending a ton of headers in response, but in case of CORS request the client[javascript in browser] is not able to access those headers unless they are not exposed. Server has to allow/handle this if client needs to access the response headers.
An example of the CORS options request
Access-Control-Request-Headers:authorization, content-type, itemsperpage, pagenumber
Access-Control-Request-Method:POST
Cache-Control:no-cache
Connection:keep-alive
Host:projectbackend.com/GetAllUsers
Origin:http://localhost:3000
This will let the server, projectbackend.com, know the headers and the method of the request that is about to happen, so if the server is good with it, it should respond with something like this
Access-Control-Allow-Headers:Content-Type, Accept, Authorization, PageNumber, ItemsPerPage
Access-Control-Allow-Methods:GET, POST, OPTIONS
Access-Control-Allow-Origin:*
Access-Control-Expose-Headers:TotalItemsCount
This tells that
Content-Type
,Accept
,Authorisation
,PageNumber
,ItemsPerPage
, are the allowed request-headersGET
,POST
andOPTIONS
are the allowed methods- Request can originate from any where and can ask for resources.
TotalItemsCount
is the only header that client can access too
In case the origin is not allowed you might get error saying
No ‘Access-Control-Allow-Origin’ header is present on the requested resource error in browser’s consoleIn most of the cases this can be fixed by allowing the origin to request for the resource such as [in php]
header("Access-Control-Allow-Origin: http://localhost:3000");
OR
In .htaccess
Header add Access-Control-Allow-Origin "*"
Header add Access-Control-Allow-Headers "origin, x-requested-with, content-type"
Header add Access-Control-Allow-Methods "PUT, GET, POST, DELETE, OPTIONS"
Don’t forget to activate the apache module headers by running a2enmod headers
in case it is not allowed yet.
And if everything goes fine, the browser will send the actual POST request and you will get the response as you expected.
I hope that this article might have given you a better understanding of CORS and how it works.
References :
https://www.w3.org/TR/cors/#security
https://developer.mozilla.org/en-US/docs/Web/HTTP/AccesscontrolCORS#Preflighted_requests