I crafted an API with Symfony 4 that uses a custom token verification. I tested the API on Postman and everything works perfectly, now I want to use the API using jQuery and fetch all the data , but in the browser, I'm facing CORS issues like below:
Access to XMLHttpRequest at 'http://localhost:8000/api/reports' from origin 'http://localhost:8080' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.
Here is my server-side API:
I've implemented a CORSEventSubscriber
to allow the CORS like below :
class CORSSubscriber implements EventSubscriberInterface
{
/**
* @var TokenStorageInterface
*/
private $tokenStorage;
public function __construct(TokenStorageInterface $tokenStorage)
{
$this->tokenStorage = $tokenStorage;
}
public function onKernelResponse(FilterResponseEvent $event)
{
$responseHeaders = $event->getResponse()->headers;
$responseHeaders->set('Access-Control-Allow-Origin', '*');
$responseHeaders->set('Access-Control-Allow-Headers', 'x-auth-token, content-type');
$responseHeaders->set('Access-Control-Allow-Methods', 'POST, GET');
}
/**
* @inheritDoc
*/
public static function getSubscribedEvents()
{
return [
KernelEvents::RESPONSE => 'onKernelResponse',
];
}
This is the action that I'm calling in the controller:
/**
* @Route("/api/reports",name="reports",methods={"GET","OPTIONS"})
* @param Request $request
* @return Response
* @throws Exception
*/
function getReports(Request $request){
return new JsonResponse('test', Response::HTTP_UNAUTHORIZED);
}
I tried consuming the API
like this
<script>
$(document).ready(function(){
authenticate().then(function (data) {
// the promise resolve the token and data.token output the correct value
$.ajax({
url:'http://localhost:8000/api/reports',
type: 'GET',
headers: {'X-Auth-Token' : data.token },
success: function (data) {
//append data to your app
console.log(data);
}
})
})
});
function authenticate() {
let data={
"username": "test",
"password": "test"
};
return new Promise(function(resolve, reject) {
$.ajax({
url:'http://localhost:8000/api/auth/check',
type:'POST',
data:JSON.stringify(data),
dataType:'Json',
success: function (data) {
console.log(data);
resolve(data);
},
error:function () {
}
})
});
}
</script>
I added this to debug closely the issue and i found out that this function only executes for POST
when there's a token method like OPTIONS
it doesn't execute
public function onKernelRequest(GetResponseEvent $event)
{
$this->logger->info($event->getRequest()->getRealMethod());
}
After days through this, I fixed it by adding to the CorsSubscriber
public function onKernelResponse(FilterResponseEvent $event)
{
$responseHeaders = $event->getResponse()->headers;
$responseHeaders->set('Access-Control-Allow-Origin', 'http://localhost:8080');
$responseHeaders->set('Access-Control-Allow-Credentials', 'true');
$responseHeaders->set('Access-Control-Allow-Headers', ' content-type ,x-auth-token');
$responseHeaders->set('Access-Control-Allow-Methods', 'POST, GET');
if($event->getRequest()->getRealMethod()=='OPTIONS'){
$responseHeaders->set('Access-Control-Max-Age', '1728000');
$event->getResponse()->setStatusCode(200);
}
}
after handling the response I send 200
as status code so I won't have any CORS
issue