CORS Post Request Fails - javascript

I built an API with the SLIM Micro-Framework. I setup some middleware that adds the CORS headers using the following code.
class Cors{
public function __invoke(Request $request, Response $response, $next){
$response = $next($request, $response);
return $response
->withHeader('Access-Control-Allow-Origin', 'http://mysite')
->withHeader('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Accept, Origin, Authorization')
->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
}
}
For my front-end, I used VueJS. I setup VueResource and created a function with the following code.
register (context, email, password) {
Vue.http({
url: 'api/auth/register',
method: 'POST',
data: {
email: email,
password: password
}
}).then(response => {
context.success = true
}, response => {
context.response = response.data
context.error = true
})
}
In chrome, the following error is logged to the console.
XMLHttpRequest cannot load http://mysite:9800/api/auth/register. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://mysite' is therefore not allowed access.
Oddly enough, GET requests work perfectly.

You half 1/2 the solution here.
What you are missing is an OPTIONS route where these headers need to be added as well.
$app->options('/{routes:.+}', function ($request, $response, $args) {
return $response
->withHeader('Access-Control-Allow-Origin', 'http://mysite')
->withHeader('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Accept, Origin, Authorization')
->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
});

This happens because preflight request is of OPTIONS type. You need to make an event listener on your request, which checks the type and sends a response with needed headers.
Unfortunately i don't know Slim framework, but here's the working example in Symfony.
First the headers example to be returned:
// Headers allowed to be returned.
const ALLOWED_HEADERS = ['Authorization', 'Origin', 'Content-Type', 'Content-Length', 'Accept'];
And in the request listener, there's a onKernelRequest method that watches all requests that are coming in:
/**
* #param GetResponseEvent $event
*/
public function onKernelRequest(GetResponseEvent $event)
{
// Don't do anything if it's not the master request
if (!$event->isMasterRequest()) {
return;
}
// Catch all pre-request events
if ($event->getRequest()->isMethod('OPTIONS')) {
$router = $this->container->get('router');
$pathInfo = $event->getRequest()->getPathInfo();
$response = new Response();
$response->headers->set('Access-Control-Allow-Origin', $event->getRequest()->headers->get('Origin'));
$response->headers->set('Access-Control-Allow-Methods', $this->getAllowedMethods($router, $pathInfo));
$response->headers->set('Access-Control-Allow-Headers', implode(', ', self::ALLOWED_HEADERS));
$response->headers->set('Access-Control-Expose-Headers', implode(', ', self::ALLOWED_HEADERS));
$response->headers->set('Access-Control-Allow-Credentials', 'true');
$response->headers->set('Access-Control-Max-Age', 60 * 60 * 24);
$response->send();
}
}
Here i just reproduce the Origin (all domains are allowed to request the resource, you should probably change it to your domain).
Hope it will give some glues.

Actually CORS is implemented at browser level. and Even with
return $response
->withHeader('Access-Control-Allow-Origin', 'http://mysite')
->withHeader('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Accept, Origin, Authorization')
->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
chrome and Mozilla will not set headers to allow cross origin. So, you need forcefully disable that..
Read more about disabling CORS
Disable same origin policy in Chrome

CORS can be hard to config. The key is that you need to set the special headers in your server and your client, and I don't see any Vue headers set, besides as far as I know http is not a function. However here is some setup for a post request.
const data = {
email: email,
password: password
}
const options = {
headers: {
'Access-Control-Expose-Headers': // all of your headers,
'Access-Control-Allow-Origin': '*'
}
}
Vue.http.post('api/auth/register', JSON.stringify(data), options).then(response => {
// success
}, response => {
// error
})
Notice that you need to stringify your data and you need to expose your headers, usually including the Access-Control-Allow-Origin header.
What I did in one of my own apps was to define interceptors so I don't worry to set headers for every request.
Vue.http.headers.common['Access-Control-Expose-Headers'] = 'Origin, X-Requested-With, Content-Type, Accept, x-session-token, timeout, Content-Length, location, *'
Vue.http.headers.common['Access-Control-Allow-Origin'] = '*'

Related

CORS blocking post requests in javascript

im making an api using Javalin and trying to send data to it from javascript, however i get cors errors whenever i try to do so. i can recieve data just fine but not send data. Here is my error: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.
-----------javascript-----------
function sendOurAjax(){
console.log("ajax using fetch")
let ourCustomSuper = {
"name": "SpaceMonkey",
"superpower": "person atmosphere",
"bounty": 0
}
fetch(`http://localhost:8000/api`, {
method: "post",
'headers': {
'Content-Type': 'application/json',
'BARNACLES': 'custom header value'
},
'body': JSON.stringify(ourCustomSuper)
})
.then(
function(daResponse){
console.log(daResponse);
const convertedResponse = daResponse.json();
return convertedResponse;
}
).then(
function(daSecondResponse){
console.log("Fetch is a thing. We did it.");
console.log(daSecondResponse);
}
).catch(
(stuff) => {console.log("this sucker exploded")}
)
}
-----------java-----------
app.get("/api", context ->{
context.header("Access-Control-Allow-Origin", "*");
context.header("Access-Control-Allow-Methods: GET, POST, PATCH, PUT, DELETE, OPTIONS");
context.header("Access-Control-Allow-Headers: Origin, Content-Type, X-Auth-Token");
System.out.println("The endpoint method has fired");
context.result("endpoint handler has fired");
context.json(myList);
});
Why was the CORS error there in the first place?
The error stems from a security mechanism that browsers implement called the same-origin policy.
The same-origin policy fights one of the most common cyber attacks out there: cross-site request forgery. In this maneuver, a malicious website attempts to take advantage of the browser’s cookie storage system.
For every HTTP request to a domain, the browser attaches any HTTP cookies associated with that domain. This is especially useful for authentication, and setting sessions. For instance, it’s feasible that you would sign into a web app like facebook-clone.com. In this case, your browser would store a relevant session cookie for the facebook-clone.com domain:
here a link on the cors subject
How To Fix CORS Error
Offhand is see you do have the
Access-Control-Allow-Origin: *
Access-Control-Allow-Origin: http://localhost:3000
set but the content type might be wrong i.e json
something along the lines of
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: Authorization, Content-Type
Content-Type: application/json

Ionic can't get open cors

I am trying to get API data from live server in ionic android app but it returns this error:
Access to XMLHttpRequest at 'https://example.com/api/categories/' from origin 'http://192.168.43.71:8100' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Server settings
Now I am using Laravel for live server which is giving the API here is how I set CORS in my laravel application:
/bootstrap/app.php
<?php
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET');
header('Access-Control-Allow-Headers: *');
// rest of the file
due to my setup above I'm getting this result on CORS tester
Ionic settings
So I've been reading how to solve this issue and came cross lots of similar solutions and this is what I add to my ionic.config.json file
"proxies": [
{
"path": "/api/*",
"proxyUrl": "https://example.com/api/"
}
]
Get request (ionic services)
Here is how I request my get method
apiUrl = 'https://example.com/api/categories/';
constructor(private http: HttpClient) { }
getCategories(): Observable<any> {
return this.http.get(`${this.apiUrl}`).pipe(
map(categories => categories)
);
}
Any idea what else should I do to fix this issue?
SOLVED
Thanks to Stephen Romero for pointing the important part of this solution,
based on stephen answer I added this code to my function:
const httpOptions = {
headers: new HttpHeaders({
'Accept': 'application/json, text/plain',
'Content-Type': 'application/json'
})
};
and used it in my get request like:
return this.http.get(`${this.apiUrl}`, httpOptions).pipe(
Now the for header permissions I used (installed) this package for on my laravel app and made config file set as code below:
return [
/*
|--------------------------------------------------------------------------
| Laravel CORS
|--------------------------------------------------------------------------
|
| allowedOrigins, allowedHeaders and allowedMethods can be set to array('*')
| to accept any value.
|
*/
'supportsCredentials' => false,
'allowedOrigins' => ['*'],
'allowedOriginsPatterns' => [],
'allowedHeaders' => ['*'],
'allowedMethods' => ['GET', 'OPTIONS'],
'exposedHeaders' => [],
'maxAge' => 0,
];
FOR those who doesn't use Laravel
Set your headers like this:
if($request_method = 'GET'){
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, OPTIONS');
header('Access-Control-Allow-Headers: Authorization, Expires, Pragma, DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range');
header("Access-Control-Expose-Headers: *");
}
The most important part of this headers is Access-Control-Allow-Headers part, if you simply use * it won't work! you need to set headers name.
Hope it helps.
Update
Forgot to mention in order to avoid error 301 you need to remove / from end of your api url.
// my api (before)
https://example.com/api/categories/
//changed to
https://example.com/api/categories
I solved my issue using these Headers for my API:
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Credentials: true ");
header("Access-Control-Allow-Methods:GET,POST");
header("Access-Control-Allow-Headers: Authorization, Content-Type, Depth, User-Agent, X-File-Size, X-Requested-With, If-Modified-Since, X-File-Name, Cache-Control");
And Angular Http:
//GET data details
getData(authToken){
const httpOptions = {
headers: new HttpHeaders({
'Accept': 'application/json, text/plain',
'Content-Type': 'application/json',
'Authorization': authToken
})
};
//console.log(authToken);
return this.http.get(this.apiGetUrl, httpOptions).retry(3);
}
Like the previous answer, an Options request automatically gets sent with the GET or POST. If you have apache servers, you can echo$headers = apache_request_headers(); to see what is all coming through. Comparison for $_SERVER and Apache here.
In my case, I run if statements:
if(isset($headers["Authorization"]) && isset($headers["Content-Type"])){
//handle get request
}
else{
//handle options request
echo " False,Re-routing Options Request";
}
I would test your HTTP call in the browser and look at dev tools to confirm the requests being sent. I hope this helps!
Perhaps at some point a preflight OPTIONS request is done by the client and since it isn't a listed method in your Access-Control-Allow-Methods it ends up in a CORS issue.
You should try to make a request to your server endpoint with OPTIONS method to check if this is the case, you can use POSTMAN to make this test.
Then try to add the OPTIONS method to the Access-Control-Allow-Methods and check the difference.

405 Method Not Allowed when using headers in the fetch api

I am trying to Make an ajax request using fetch, and when I do, I get a 405 (Method Not Allowed) error.
I am executing it like this:
fetch(url, {
method: 'get',
headers: {
'Game-Token': '123'
}
});
And that is giving me an error. If I remove the headers, the request goes through. However, I need that header for validation on the server.
fetch(url, { method: 'get' });
I have the following setup in my .htaccess file:
Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS, FETCH"
Header set Access-Control-Allow-Credentials "true"
Header set Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept, Authorization, X-CSRF-TOKEN, Game-Token, developerKey"
Header set X-Frame-Options "SAMEORIGIN"
Header set Access-Control-Expose-Headers "Game-Token"
I am not sure what is causing this to not go through.
So, this had nothing to do with JavaScript or the .htaccess. Instead it has to do with Lumen. We need to catch the OPTIONS request and reply back. What we did was create a middleware file that checked for the OPTIONS method and responds with a 200.
use Closure;
class CorsMiddleware
{
public function handle($request, Closure $next)
{
if ($request->isMethod('OPTIONS'))
{
return response('',200);
}
return $next($request);
}
}

CORS - Access-Control-Allow-Origin issue

I have an AngularJS web application with a RESTful Jersey Api as Backend.
I'm making a call to this API
function Create(user) {
return $http.post('http://localhost:8080/NobelGrid/api/users/create/', user).then(handleSuccess, handleError('Error creating user'));
}
This is the code of the API (POST):
/**
* This API create an user
*
* #param data
* #return
*/
#Path("create")
#POST
#Produces("application/json")
public Response create(String data) {
UserDataConnector connector;
JSONObject response = new JSONObject(data);
User userToCreate = new User(response.getString("surname"), response.getString("name"),
response.getString("mail"), response.getString("username"), response.getString("password"), 0);
try {
connector = new UserDataConnector();
connector.createUser(userToCreate);
} catch (IOException e) {
e.printStackTrace();
}
return Response.status(Response.Status.OK) // 200
.entity(userToCreate)
.header("Access-Control-Allow-Origin", "*")
.header("Access-Control-Allow-Headers", "X-Requested-With, Content-Type, X-Codingpedia,Authorization")
.header("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT").build();
}
/**
* CORS compatible OPTIONS response
*
* #return
*/
#Path("/create")
#OPTIONS
public Response createOPT() {
System.out.println("Called OPTION for create API");
return Response.status(Response.Status.OK) // 200
.header("Access-Control-Allow-Origin", "*")
.header("Access-Control-Allow-Headers", "X-Requested-With, Content-Type, X-Codingpedia,Authorization")
.header("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT, OPTIONS").build();
}
I've added an OPTION API for create in order to make that API CORS-compatible. In fact the API works well cause the OPTIONS API is called before the POST one and the user is created in my Database. Anyway on front end side I get this error:
XMLHttpRequest cannot load http://localhost:8080/NobelGrid/api/users/create/. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:63342' is therefore not allowed access. The response had HTTP status code 500.
Can anyone please help me?
UPDATE:
stack suggests this question No Access-Control-Allow-Origin header is present on the requested resource as possible duplicate but that solution doesn't work for me cause addHeader(String) is not present in Response Jersey API.
UPDATE 2
I solved the issue using this solution:
http://www.coderanch.com/t/640189/Web-Services/java/Access-Control-Origin-header-present
But I have another error. I will do another question cause I think it's a different argument.
Thanks in advanced!
I solved the issue using this solution:
http://www.coderanch.com/t/640189/Web-Services/java/Access-Control-Origin-header-present
But I have another error.
I will do another question cause I think it's a different argument.
Use CORS NPM and add as a middleware.
var express = require('express')
var cors = require('cors')
var app = express()
app.use(cors())
app.get('/products/:id', function (req, res, next) {
res.json({msg: 'This is CORS-enabled for all origins!'})
})
app.listen(80, function () {
console.log('CORS-enabled web server listening on port 80')
})
------------------------- Add this lines in your app.js -------------------------
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, PATCH, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: Origin, Content-Type, X-Auth-Token');

Angular http post request - No 'Access-Control-Allow-Origin' header is present on the requested resource

I am trying to send data to servlet using angular http post,
var httpPostData = function (postparameters,postData){
var headers = {
'Access-Control-Allow-Origin' : '*',
'Access-Control-Allow-Methods' : 'POST, GET, OPTIONS',
'Accept': 'application/json'
};
return $http ({
method : 'POST',
url : 'http://localhost:8080/json/jasoncontroller',
params : postparameters,
headers: headers,
data : postData
}).success (function (responseData){
return responseData.data;
})
}
But i am keep on getting error that No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.
I did have set following headers on my servlet
response.addHeader("Access-Control-Allow-Origin", "*");
response.addHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE");
response.addHeader("Access-Control-Max-Age", "3600");
response.addHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
if i remove data from http post it works fine, but no luck with data.
Actually what happens is in some frameworks two calls are made,
OPTIONS which checks what methods are available,
And then there is the actual call.
OPTIONS require just empty answer 200 OK
if(request.methord == 'OPTIONS'){
res.send(200);
} else {
next();
}
You can also install this chrome extension to enable cors, that is the easy way out !

Categories

Resources