CORS Preflight error with Apache, Laravel and AngularJS - angularjs

I have implemented a backend with an Apache server with AMI from AWS and Laravel. For authentication I use the JWT Auth plugin.
My frontend is build with AngularJS. Before using the authentication everything worked fine. When I try to authenticate the user with an authorization header I get a CORS Preflight error. I use the following call from my AngularJS application:
delete $http.defaults.headers.common['X-Requested-With'];
$http.defaults.headers.common.Accept = "text/plain";
$http({
url: 'http://MYURL',
method: "GET",
headers: {
'Access-Control-Allow-Headers': 'Authorization, Content-Type, Accept',
'Content-Type' : 'text/plain',
'Authorization': 'Bearer '+token,
}
})
In my Laravel backend I used the following configuration:
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: Authorization, Content-Type");
This is the response from the OPTIONS call:
This is the error I get in Google Chrome:
Request header field Authorization is not allowed by Access-Control-Allow-Headers in preflight response.
Any ideas on this issue? Do I have to configure this within Angular, Laravel or my httpd.conf?
EDIT:
I added it as a global Middleware and in the app.php as service provider.
The configuration looks like this:
return [
'supportsCredentials' => false,
'allowedOrigins' => ['*'],
'allowedHeaders' => ['Authorization, Content-Type'],
'allowedMethods' => ['*'],
'exposedHeaders' => [],
'maxAge' => 0,
'hosts' => [],
];
But I have no idea if it works correctly.

Have you considered using a plugin for managing CORS setup like this one?
It appears that the list of headers you allow on the server side (Authorization, Content-Type) is not the same as the list of headers being sent by the request (Authorization, Content-Type, Accept). It could be that the front end is asking for permissions that you aren't allowing on the back end.

Related

Problem with cors between backend and frontend

I have a problem with my cors policy between my backend (API Rest in .NET Core 6) and my frontend (in ReactJS), the thing is that in my backend I have the following configuration:
In appsetings.json:
"AllowedHosts": "mywebsite.com"
In Program.cs:
services.AddCors(options =>
{
options.AddPolicy(name: "mycors", builder =>
{
builder.WithOrigins("mywebsite.com")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
app.UseCors("mycors");
This configuration doesn't work when I'm trying to fetch a post request to my API, but if I change the AllowedHosts to "AllowedHosts": "*" it works. I don't understand why I can't allow just to my frontend website.
Additional information, my post request has these parameters:
method: 'POST'
mode: 'cors',
cache: 'no-cache',
credentials: 'same-origin',
redirect: 'follow',
referrerPolicy: 'no-referrer',
headers: { 'Content-Type': 'application/json' },
body: //My parameters
The console error is:
Access to fetch at 'mybackendpostmethod' from origin 'myfronturl.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
I solved putting my api that return as follows

CSRF cookie not set [Django/AngularJS]

First of all, this is not a duplicate question. I have tried all the related posts on stackoverflow but could not find a solution.
I have a Django app for the backend and and AngularJS app for the frontend. I am using djangorestframework-jwt for API authentication. I have an API endpoint that does not require any authentication and I am getting CSRF Failed: CSRF cookie not set error on the browser only for this endpoint.
In my django settings I have:
ALLOWED_HOSTS = ['*']
and it does not include any CSRF_COOKIE_SECURE, CSRF_COOKIE_HTTPONLY, or SESSION_COOKIE_SECURE settings.
The djangorestframework-jwt settings is:
JWT_AUTH = {
'JWT_SECRET_KEY': SECRET_KEY,
'JWT_ALGORITHM': 'HS256',
'JWT_VERIFY': True,
'JWT_VERIFY_EXPIRATION': True,
'JWT_EXPIRATION_DELTA': datetime.timedelta(seconds=3000),
'JWT_ALLOW_REFRESH': True,
'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(days=1),
'JWT_AUTH_COOKIE': 'refresh-token'
}
I noticed that in the browser cookies if there is any refresh-token key then the endpoint works just fine. The problem arises when that key is not present in the browser cookies. I set 'JWT_AUTH_COOKIE': None or removed the following lines:
'JWT_ALLOW_REFRESH': True,
'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(days=1),
'JWT_AUTH_COOKIE': 'refresh-token'
from the JWT_AUTH settings but no luck.
I also tried #csrf_excempt for that endpoint but that did not work either.
Interestingly, when I send the request from postman it works.
Here is the request I am sending from the frontend:
$http({
url: url,
method: "PUT",
headers: {
'Content-Type': 'application/json'
},
data: data
})
I would like to know why I am getting the error when refresh_token key is not present in the browser cookies and how to solve this issue.
I solved my issue by adding 'X-CSRFToken': $cookies.get("csrftoken") to the Http request header, so the request now look like:
$http({
url: url,
method: "PUT",
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': $cookies.get("csrftoken")
},
data: data
})

Call symfony 2 rest api with Angular JS, cors

I'm using angularJS to call a restfull API in symfony 2.
My angularJS app url is angular.me.dev
My symfony2 api url is api.me.dev
I followed this tutorial to make my restfull api.
The problem is when I try to call this api
$http.({
method: 'GET',
url: 'http://api.me.dev/api/articles',
headers: {
'Authorization': 'Bearer ' + token
}
})
An error occured: (here on google chrome):
XMLHttpRequest cannot load http://api.me.dev/api/articles. Response for preflight has invalid HTTP status code 405
(and on on firefox):
The Same Origin Policy disallows reading the remote resource
what did I find about this ?
AngularJS Sends OPTIONS request instead of POST
AngularJS performs an OPTIONS HTTP request for a cross-origin resource
Then I decide to allow headers, origin, ... on my server like this:
Header always set Access-Control-Allow-Origin "*"
Header always set Access-Control-Allow-Credentials "true"
Header always set Access-Control-Allow-Methods "PUT, DELETE, POST, GET, OPTIONS"
Header always set Access-Control-Allow-Headers "*"
No change
I add to AngularJS
#coffee script
app.config ['$httpProvider', ($httpProvider) ->
$httpProvider.defaults.useXDomain = true
delete $httpProvider.defaults.headers.common['X-Requested-With']
]
Then I decided to install NelmioCorsBundle in my symfony api but I didn't see any change.
Finally, I notice a call works
$http.({
method: 'GET',
url: 'http://api.me.dev/api/articles',
})
Here the call return a 401 response (good, i need to be logged)
$http.({
method: 'GET',
url: 'http://api.me.dev/public/api/users',
})
Here I have a call doesn't need authorization, it works.
I found only when I remove headers it works, and when I had any headers (content-type or authorization for example) an error occured.
Can anyone help me ? thanks !
Ok, my bad.
I said NelmioCors seems not working but i did something wrong.
I try again with nelmio cors bundle, using this configuration.
nelmio_cors:
paths:
'^/':
allow_origin: ['http://angular.me.dev']
allow_headers: ['Authorization', 'X-Requested-With', 'Content-Type', 'Accept', 'Origin', 'X-Custom-Auth']
allow_methods: ['POST', 'PUT', 'GET', 'DELETE', 'OPTIONS']
max_age: 3600
It's working !
NelmioCorsBundle resolve the problem.
https://github.com/nelmio/NelmioCorsBundle

CORS error with AngularJS post only in FireFox

I am having issues only with FireFox when making a cross origin request in an Ionic app (so it's using AngularJS). The js app is doing a $http.post() to a Laravel 5.1 API, and I get the following error only in FireFox (39.0.3):
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://blah.dev/endpoint. (Reason: missing token 'content-type' in CORS header 'Access-Control-Allow-Headers' from CORS preflight channel).
This is on my localhost (OSX Mavericks). and works fine in Chrome and Safari, only FireFox is given the error. I have cleared the cache, and tried in a "private window", with the same results.
Here is the Laravel route defined to handle the OPTIONS request:
Route::options('endpoint', function() {
return response('OK')
->header('Access-Control-Allow-Headers ', 'Origin, Authorization, X-Requested-With, Content-Type, Accept')
->header('Access-Control-Allow-Methods', 'POST, GET, OPTIONS')
->header('Access-Control-Allow-Origin', '*')
->header('Cache-Control', 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0')
;
});
Route::post('endpoint', array('uses' => '\Path\To\Controller#endpoint'));
I did find this question that seems to have a similar issue only in FireFox, but the solution was to comma separate the Allow-Methods, which I already am.
The message " missing token 'content-type' " is about the client. For a http request to be a valid post one, it must have a header
'Content-Type': 'application/x-www-form-urlencoded'
or
'Content-Type': 'multipart/form-data'
The first content-type is the most common one.
In angularjs one way to do a CORS post request is
$http.post(
'http://external-domain.ext/the/rest/url',
'param_name=param_value',
{headers:{'Content-Type': 'application/x-www-form-urlencoded'}}
).
then(function successCallback(response) {
$scope.something = response;
}, function errorCallback(response) {
// not good
});
If the server is configured with
header('Access-Control-Allow-Origin', '*'), the CORS post must succeed without authentication and credentials.
on the back end try putting
->header('Access-Control-Allow-Credentials', 'true')
and on the front end try putting
.config(function($locationProvider, $httpProvider) {
// CORS requests with credentials
$httpProvider.defaults.withCredentials = true;
})

CORS the easyway

I'm trying to 'put' data to my Laravel 5 server running on localhost from a webpage thats is also served localhost, but from other server software (nodejs). But im getting this error:
XMLHttpRequest cannot load http://localhost:8888/data/. Method PUT is not allowed by Access-Control-Allow-Methods.
The code that creates the put request is angularjs and looks like this:
return $http.put("http://localhost:8888/data/", { obj1: a, obj2: b });
What is the simplest way to get around CORS? Security is no issue.
Using the postman plug-in in chrome I'm able to send the put request.
This is my laravel setup for cors.
I've created an http.php config file with this settings:
return [
'cors' => [
'origin' => '*',
'methods' => 'OPTIONS, GET, POST, PUT, PATCH, DELETE',
'headers' => 'X-Requested-With, Content-Type, Authentication-Token',
],
];
Run this code somewhere on application startup:
if ( ! App::runningInConsole()) {
header('Access-Control-Allow-Origin: ' . Config::get('http.cors.origin'));
header('Access-Control-Allow-Credentials: true'); // to be honest i've never used this option, but it looks like you'll need it
// handle preflight requests
App::before(function() {
if (Request::getMethod() === 'OPTIONS') {
return new Response('', 200, [
'Access-Control-Allow-Methods' => Config::get('http.cors.methods'),
'Access-Control-Allow-Headers' => Config::get('http.cors.headers'),
]);
}
});
}
Postman doesn't use CORS.
To enable CORS (in the client side) add : { withCredentials: true } in your put options :
return $http.put("http://localhost:8888/data/", { obj1: a, obj2: b }, { withCredentials: true });
Note: Depending on your server application, you may enable them in the server side too.
It doesn't seem to be an Angular problem. You should try enabling CORS on the PHP with:
// Enable CORS
// In production, replace * with http://yourdomain.com
header("Access-Control-Allow-Origin: *");
header('Access-Control-Allow-Credentials: true');

Resources