Related
I have a simple PHP script that I am attempting a cross-domain CORS request:
<?php
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: *");
...
Yet I still get the error:
Request header field X-Requested-With is not allowed by Access-Control-Allow-Headers
Anything I'm missing?
Handling CORS requests properly is a tad more involved. Here is a function that will respond more fully (and properly).
/**
* An example CORS-compliant method. It will allow any GET, POST, or OPTIONS requests from any
* origin.
*
* In a production environment, you probably want to be more restrictive, but this gives you
* the general idea of what is involved. For the nitty-gritty low-down, read:
*
* - https://developer.mozilla.org/en/HTTP_access_control
* - https://fetch.spec.whatwg.org/#http-cors-protocol
*
*/
function cors() {
// Allow from any origin
if (isset($_SERVER['HTTP_ORIGIN'])) {
// Decide if the origin in $_SERVER['HTTP_ORIGIN'] is one
// you want to allow, and if so:
header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}");
header('Access-Control-Allow-Credentials: true');
header('Access-Control-Max-Age: 86400'); // cache for 1 day
}
// Access-Control headers are received during OPTIONS requests
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD']))
// may also be using PUT, PATCH, HEAD etc
header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']))
header("Access-Control-Allow-Headers: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}");
exit(0);
}
echo "You have CORS!";
}
Security Notes
Check the HTTP_ORIGIN header against a list of approved origins.
If the origin isn't approved, then you should deny the request.
Please read the spec.
TL;DR
When a browser wants to execute a cross-site request it first confirms that this is okay with a "pre-flight" request to the URL. By allowing CORS you are telling the browser that responses from this URL can be shared with other domains.
CORS does not protect your server. CORS attempts to protect your users by telling browsers what the restrictions should be on sharing responses with other domains. Normally this kind of sharing is utterly forbidden, so CORS is a way to poke a hole in the browser's normal security policy. These holes should be as small as possible, so always check the HTTP_ORIGIN against some kind of internal list.
There are some dangers here, especially if the data the URL serves up is normally protected. You are effectively allowing browser content that originated on some other server to read (and possibly manipulate) data on your server.
If you are going to use CORS, please read the protocol carefully (it is quite small) and try to understand what you're doing. A reference URL is given in the code sample for that purpose.
Header security
It has been observed that the HTTP_ORIGIN header is insecure, and that is true. In fact, all HTTP headers are insecure to varying meanings of the term. Unless a header includes a verifiable signature/hmac, or the whole conversation is authenticated via TLS, headers are just "something the browser has told me".
In this case, the browser is saying "an object from domain X wants to get a response from this URL. Is that okay?" The point of CORS is to be able to answer, "yes I'll allow that".
I got the same error, and fixed it with the following PHP in my back-end script:
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST');
header("Access-Control-Allow-Headers: X-Requested-With");
Access-Control-Allow-Headers does not allow * as accepted value, see the Mozilla Documentation here.
Instead of the asterisk, you should send the accepted headers (first X-Requested-With as the error says).
Update:
* is now accepted is Access-Control-Allow-Headers.
According to MDN Web Docs 2021:
The value * only counts as a special wildcard value for requests without credentials (requests without HTTP cookies or HTTP authentication information). In requests with credentials, it is treated as the literal header name * without special semantics. Note that the Authorization header can't be wildcarded and always needs to be listed explicitly.
Many description internet-wide don't mention that specifying Access-Control-Allow-Origin is not enough. Here is a complete example that works for me:
<?php
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, GET, DELETE, PUT, PATCH, OPTIONS');
header('Access-Control-Allow-Headers: token, Content-Type');
header('Access-Control-Max-Age: 1728000');
header('Content-Length: 0');
header('Content-Type: text/plain');
die();
}
header('Access-Control-Allow-Origin: *');
header('Content-Type: application/json');
$ret = [
'result' => 'OK',
];
print json_encode($ret);
I've simply managed to get dropzone and other plugin to work with this fix (angularjs + php backend)
header('Access-Control-Allow-Origin: *');
header("Access-Control-Allow-Credentials: true");
header('Access-Control-Allow-Methods: GET, PUT, POST, DELETE, OPTIONS');
header('Access-Control-Max-Age: 1000');
header('Access-Control-Allow-Headers: Origin, Content-Type, X-Auth-Token , Authorization');
add this in your upload.php or where you would send your request (for example if you have upload.html and you need to attach the files to upload.php, then copy and paste these 4 lines).
Also if you're using CORS plugins/addons in chrome/mozilla be sure to toggle them more than one time,in order for CORS to be enabled
If you want to create a CORS service from PHP, you can use this code as the first step in your file that handles the requests:
// Allow from any origin
if(isset($_SERVER["HTTP_ORIGIN"]))
{
// You can decide if the origin in $_SERVER['HTTP_ORIGIN'] is something you want to allow, or as we do here, just allow all
header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}");
}
else
{
//No HTTP_ORIGIN set, so we allow any. You can disallow if needed here
header("Access-Control-Allow-Origin: *");
}
header("Access-Control-Allow-Credentials: true");
header("Access-Control-Max-Age: 600"); // cache for 10 minutes
if($_SERVER["REQUEST_METHOD"] == "OPTIONS")
{
if (isset($_SERVER["HTTP_ACCESS_CONTROL_REQUEST_METHOD"]))
header("Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE, PUT"); //Make sure you remove those you do not want to support
if (isset($_SERVER["HTTP_ACCESS_CONTROL_REQUEST_HEADERS"]))
header("Access-Control-Allow-Headers: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}");
//Just exit with 200 OK with the above headers for OPTIONS method
exit(0);
}
//From here, handle the request as it is ok
CORS can become a headache, if we do not correctly understand its functioning. I use them in PHP and they work without problems. reference here
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Credentials: true");
header("Access-Control-Max-Age: 1000");
header("Access-Control-Allow-Headers: X-Requested-With, Content-Type, Origin, Cache-Control, Pragma, Authorization, Accept, Accept-Encoding");
header("Access-Control-Allow-Methods: PUT, POST, GET, OPTIONS, DELETE");
This much code works down for me when using angular 4 as the client side and PHP as the server side.
header("Access-Control-Allow-Origin: *");
this should work
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: X-Requested-With, Content-Type, Origin, Cache-Control, Pragma, Authorization, Accept, Accept-Encoding");
I used these 5 headers and after that solved the cors error(backend: PHP, Frontend: VUE JS)
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, PUT, POST, DELETE, OPTIONS, post, get');
header("Access-Control-Max-Age", "3600");
header('Access-Control-Allow-Headers: Origin, Content-Type, X-Auth-Token');
header("Access-Control-Allow-Credentials", "true");
add this code in .htaccess
add custom authentication key's in header like app_key,auth_key..etc
Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Headers: "customKey1,customKey2, headers, Origin, X-Requested-With, Content-Type, Accept, Authorization"
So I know there's a lot of CORS posts out there, and I'm just adding to them, but I can't find any with answers that help me out. So I'm building an angular 4 application that relies on my php api. Working locally it's fine, the moment I toss it up on the domain with the app at app.example.com, and the api at api.example.com, I can't get past my login, because I get the following error:
XMLHttpRequest cannot load http://api.example.com/Account/Login.
Response to preflight request doesn't pass access control check: No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://app.example.com' is therefore not allowed
access.
My php code looks like this:
$http_origin = $_SERVER['HTTP_ORIGIN'];
$allowed_domains = array(
'http://example.com',
'https://example.com',
'http://app.example.com',
'https://app.example.com',
'http://www.example.com',
'https://www.example.com'
);
if (in_array(strtolower($http_origin), $allowed_domains))
{
// header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Origin: $http_origin");
header('Access-Control-Allow-Credentials: true');
header('Access-Control-Max-Age: 86400');
}
// Access-Control headers are received during OPTIONS requests
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
header("Access-Control-Allow-Headers: Authorization, Content-Type,Accept, Origin");
exit(0);
}
My Angular post looks like this:
public login(login: Login): Observable<LoginResponse> {
let headers = new Headers();
headers.append('Content-Type', 'application/x-www-form-urlencoded');
headers.append('Authorization', 'Basic ' + btoa(login.Username + ':' + login.Password));
return this.http.post(this.apiBaseUrl + '/Account/Login', "grant_type=client_credentials", { headers: headers })
.map(response => {
// code
});
}
If I run the request through postman, which doesn't bother with CORS, I get:
{ "error": "invalid_client", "error_description": "Client credentials were not found in the headers or body" }
I've tried setting origin to '*' just to test and see if that was the core of the issue, and it still fails the same way.
Edit
Just updating from information below. Changing casing in headers had no effect, and pulling the code out of their if statements had no effect.
I debugged the php by telling my live app to go to my local api, and the php is working as expected. It's setting the headers and making it into each of the if statements.
Edit take 2
I could really use some help on this one, if someone has any ideas, I'd really appreciate it.
Edit take 3
If I set all the header stuff in my .htaccess rather than my php, it lets me through. However, now I'm stuck on the error listed above that I always get when using postman, however now it's while using the actual site.
{"error":"invalid_client","error_description":"Client credentials were not found in the headers or body"}
My response headers are like so
Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:authorization, content-type, accept, origin
Access-Control-Allow-Methods:GET, POST, OPTIONS
Access-Control-Allow-Origin:*
I'll be changing it from * to only my domains once I have it working. But for now i'll leave it as *.
My headers as requested.
OK I had a similar issues recently and I solved everything only on the backend side with no .htaccess stuff.
when the browser sends cross server requests it firsts sends an OPTIONS request to make sure it is valid and it can send the "real" request.
After it gets a proper and valid response from OPTIONS, only then it sends the "real" request.
Now for both request on the backend you need to make sure to return the proper headers: content-type, allow-origin, allow-headers etc...
Make sure that in the OPTIONS request on the backend, the app returns the headers and returns the response, not continuing the full flow of the app.
In the "real" request, you should return the proper headers and your regular response body.
example:
//The Response object
$res = $app->response;
$res->headers->set('Content-Type', 'application/json');
$res->headers->set('Access-Control-Allow-Origin', 'http://example.com');
$res->headers->set('Access-Control-Allow-Credentials', 'true');
$res->headers->set('Access-Control-Max-Age', '60');
$res->headers->set('Access-Control-Allow-Headers', 'AccountKey,x-requested-with, Content-Type, origin, authorization, accept, client-security-token, host, date, cookie, cookie2');
$res->headers->set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
if ( ! $req->isOptions()) {
// this continues the normal flow of the app, and will return the proper body
$this->next->call();
} else {
//stops the app, and sends the response
return $res;
}
Things to remember:
if you are using: "Access-Control-Allow-Credentials" = true
make sure that "Access-Control-Allow-Origin" is not "*", it must be set with a proper domain!
( a lot of blood was spilled here :/ )
define the allowed headers you will get in "Access-Control-Allow-Headers"
if you wont define them, the request will fail
if you using "Authorization: Bearer", then "Access-Control-Allow-Headers" should also contain "Authorization", if not, the request will fail
In my similar case with Angular frontend and Php backend helped code below. Firstly I send a headers:
header("Access-Control-Allow-Origin: http://localhost:4200");
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Methods: POST, DELETE, OPTIONS");
header("Access-Control-Max-Age: 3600");
header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
And after them I'm enable ignoring the options request:
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
return 0;
}
This approach helped me handling the "post" and the "delete" embedded request methods from the Angular.
I added below in php and it solved my problem.
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: Content-Type, origin");
I had a similar issue,
Dev environment: Apache web server behind NginX Proxy
My app is in a virtual host in my Apache server,
configured with name: appname.devdomain.com
When accessing to web app internaly I wasn´t getting through the proxy:
I was using the url: appname.devdomain.com
I had no problem this way.
But, when accessing it externally using public url: appname.prddomain.com
it would load, even got access to the system after login, then load the templates and some session content, then, if an asynchronous call would be made by the client then I would got the following message in chrome console:
"Access to XMLHttpRequest at 'http://appname.devdomain.com/miAdminPanel.php' from origin 'http://appname.prddomain.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request."
To test this I opened two tabs
1st tab accessed the web using url: appname.devdomain.com, made XMLHttpRequest -> OK
2nd tab accessed the web using url: appname.prddomain.com, made XMLHttpRequest -> CORS error message above.
So, after changing the Nginx proxy configuration:
server {
listen 80;
server_name appname.prddomain.com;
# SSL log files ###
access_log /path/to/acces-log.log;
error_log /path/to/error-log.log;
location / {
proxy_pass http://appname.devdomain.com;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
basically this tells the proxy to treat the external request as internal request.
i am struggling with this error
cors error header disallowed by preflight response
tried almost all possible combination but chrome is continuously throwing this error
i have tried these headers from php
// header('Access-Control-Allow-Origin: stylishgames.myshopify.com');
header('Access-Control-Allow-Origin: *');
// header('Access-Control-Allow-Methods: POST, GET, OPTIONS');
// header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Content-Type: application/json;charset=UTF-8');
// header('Access-Control-Allow-Origin: * ');
header('Access-Control-Allow-Methods: HEAD, GET, OPTIONS, POST, PUT');
header('Access-Control-Allow-Headers: Content-Type, Content-Range, Content-Disposition, Content-Description');
header('Access-Control-Max-Age: 1728000');
header('Access-Control-Allow-Credentials', 'true');
same thing can be checked live at this site
go to this page
https://stylishgames.myshopify.com/products/test-product1
click on add to cart and then in bottom you can see campaign_page.php in network tab when you click on ADD to cart and then click next and this error will appear,
any help will be great
Explicitly allow headers required by the browser's request. Get the full list from the Access-Control-Request-Headers field of the preflight request.
Explanation
The browser sends the preflight request to inquire whether the server hosting the cross-origin resource will permit the actual request. The preflight's Access-Control-Request-Headers field lists the headers the request will use. The server response contains the complementary Access-Control-Allow-Headers field, specifying the allowed headers (See Mozilla docs)
The Header Disallowed By Preflight Response error appeared because your server doesn't allow some of the headers from the browser's request. To see which ones are missing, look at the preflight request sent by Chrome. You can access it on the Network tab.
Access-Control-Allow-Origin and Access-Control-Allow-Methods were irrelevant to the error — that's why changing them had no effect.
I have a simple PHP script that I am attempting a cross-domain CORS request:
<?php
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: *");
...
Yet I still get the error:
Request header field X-Requested-With is not allowed by Access-Control-Allow-Headers
Anything I'm missing?
Handling CORS requests properly is a tad more involved. Here is a function that will respond more fully (and properly).
/**
* An example CORS-compliant method. It will allow any GET, POST, or OPTIONS requests from any
* origin.
*
* In a production environment, you probably want to be more restrictive, but this gives you
* the general idea of what is involved. For the nitty-gritty low-down, read:
*
* - https://developer.mozilla.org/en/HTTP_access_control
* - https://fetch.spec.whatwg.org/#http-cors-protocol
*
*/
function cors() {
// Allow from any origin
if (isset($_SERVER['HTTP_ORIGIN'])) {
// Decide if the origin in $_SERVER['HTTP_ORIGIN'] is one
// you want to allow, and if so:
header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}");
header('Access-Control-Allow-Credentials: true');
header('Access-Control-Max-Age: 86400'); // cache for 1 day
}
// Access-Control headers are received during OPTIONS requests
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD']))
// may also be using PUT, PATCH, HEAD etc
header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']))
header("Access-Control-Allow-Headers: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}");
exit(0);
}
echo "You have CORS!";
}
Security Notes
Check the HTTP_ORIGIN header against a list of approved origins.
If the origin isn't approved, then you should deny the request.
Please read the spec.
TL;DR
When a browser wants to execute a cross-site request it first confirms that this is okay with a "pre-flight" request to the URL. By allowing CORS you are telling the browser that responses from this URL can be shared with other domains.
CORS does not protect your server. CORS attempts to protect your users by telling browsers what the restrictions should be on sharing responses with other domains. Normally this kind of sharing is utterly forbidden, so CORS is a way to poke a hole in the browser's normal security policy. These holes should be as small as possible, so always check the HTTP_ORIGIN against some kind of internal list.
There are some dangers here, especially if the data the URL serves up is normally protected. You are effectively allowing browser content that originated on some other server to read (and possibly manipulate) data on your server.
If you are going to use CORS, please read the protocol carefully (it is quite small) and try to understand what you're doing. A reference URL is given in the code sample for that purpose.
Header security
It has been observed that the HTTP_ORIGIN header is insecure, and that is true. In fact, all HTTP headers are insecure to varying meanings of the term. Unless a header includes a verifiable signature/hmac, or the whole conversation is authenticated via TLS, headers are just "something the browser has told me".
In this case, the browser is saying "an object from domain X wants to get a response from this URL. Is that okay?" The point of CORS is to be able to answer, "yes I'll allow that".
I got the same error, and fixed it with the following PHP in my back-end script:
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST');
header("Access-Control-Allow-Headers: X-Requested-With");
Access-Control-Allow-Headers does not allow * as accepted value, see the Mozilla Documentation here.
Instead of the asterisk, you should send the accepted headers (first X-Requested-With as the error says).
Update:
* is now accepted is Access-Control-Allow-Headers.
According to MDN Web Docs 2021:
The value * only counts as a special wildcard value for requests without credentials (requests without HTTP cookies or HTTP authentication information). In requests with credentials, it is treated as the literal header name * without special semantics. Note that the Authorization header can't be wildcarded and always needs to be listed explicitly.
Many description internet-wide don't mention that specifying Access-Control-Allow-Origin is not enough. Here is a complete example that works for me:
<?php
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, GET, DELETE, PUT, PATCH, OPTIONS');
header('Access-Control-Allow-Headers: token, Content-Type');
header('Access-Control-Max-Age: 1728000');
header('Content-Length: 0');
header('Content-Type: text/plain');
die();
}
header('Access-Control-Allow-Origin: *');
header('Content-Type: application/json');
$ret = [
'result' => 'OK',
];
print json_encode($ret);
I've simply managed to get dropzone and other plugin to work with this fix (angularjs + php backend)
header('Access-Control-Allow-Origin: *');
header("Access-Control-Allow-Credentials: true");
header('Access-Control-Allow-Methods: GET, PUT, POST, DELETE, OPTIONS');
header('Access-Control-Max-Age: 1000');
header('Access-Control-Allow-Headers: Origin, Content-Type, X-Auth-Token , Authorization');
add this in your upload.php or where you would send your request (for example if you have upload.html and you need to attach the files to upload.php, then copy and paste these 4 lines).
Also if you're using CORS plugins/addons in chrome/mozilla be sure to toggle them more than one time,in order for CORS to be enabled
If you want to create a CORS service from PHP, you can use this code as the first step in your file that handles the requests:
// Allow from any origin
if(isset($_SERVER["HTTP_ORIGIN"]))
{
// You can decide if the origin in $_SERVER['HTTP_ORIGIN'] is something you want to allow, or as we do here, just allow all
header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}");
}
else
{
//No HTTP_ORIGIN set, so we allow any. You can disallow if needed here
header("Access-Control-Allow-Origin: *");
}
header("Access-Control-Allow-Credentials: true");
header("Access-Control-Max-Age: 600"); // cache for 10 minutes
if($_SERVER["REQUEST_METHOD"] == "OPTIONS")
{
if (isset($_SERVER["HTTP_ACCESS_CONTROL_REQUEST_METHOD"]))
header("Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE, PUT"); //Make sure you remove those you do not want to support
if (isset($_SERVER["HTTP_ACCESS_CONTROL_REQUEST_HEADERS"]))
header("Access-Control-Allow-Headers: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}");
//Just exit with 200 OK with the above headers for OPTIONS method
exit(0);
}
//From here, handle the request as it is ok
CORS can become a headache, if we do not correctly understand its functioning. I use them in PHP and they work without problems. reference here
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Credentials: true");
header("Access-Control-Max-Age: 1000");
header("Access-Control-Allow-Headers: X-Requested-With, Content-Type, Origin, Cache-Control, Pragma, Authorization, Accept, Accept-Encoding");
header("Access-Control-Allow-Methods: PUT, POST, GET, OPTIONS, DELETE");
This much code works down for me when using angular 4 as the client side and PHP as the server side.
header("Access-Control-Allow-Origin: *");
this should work
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: X-Requested-With, Content-Type, Origin, Cache-Control, Pragma, Authorization, Accept, Accept-Encoding");
I used these 5 headers and after that solved the cors error(backend: PHP, Frontend: VUE JS)
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, PUT, POST, DELETE, OPTIONS, post, get');
header("Access-Control-Max-Age", "3600");
header('Access-Control-Allow-Headers: Origin, Content-Type, X-Auth-Token');
header("Access-Control-Allow-Credentials", "true");
add this code in .htaccess
add custom authentication key's in header like app_key,auth_key..etc
Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Headers: "customKey1,customKey2, headers, Origin, X-Requested-With, Content-Type, Accept, Authorization"
I have a simple PHP script that I am attempting a cross-domain CORS request:
<?php
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: *");
...
Yet I still get the error:
Request header field X-Requested-With is not allowed by Access-Control-Allow-Headers
Anything I'm missing?
Handling CORS requests properly is a tad more involved. Here is a function that will respond more fully (and properly).
/**
* An example CORS-compliant method. It will allow any GET, POST, or OPTIONS requests from any
* origin.
*
* In a production environment, you probably want to be more restrictive, but this gives you
* the general idea of what is involved. For the nitty-gritty low-down, read:
*
* - https://developer.mozilla.org/en/HTTP_access_control
* - https://fetch.spec.whatwg.org/#http-cors-protocol
*
*/
function cors() {
// Allow from any origin
if (isset($_SERVER['HTTP_ORIGIN'])) {
// Decide if the origin in $_SERVER['HTTP_ORIGIN'] is one
// you want to allow, and if so:
header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}");
header('Access-Control-Allow-Credentials: true');
header('Access-Control-Max-Age: 86400'); // cache for 1 day
}
// Access-Control headers are received during OPTIONS requests
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD']))
// may also be using PUT, PATCH, HEAD etc
header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']))
header("Access-Control-Allow-Headers: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}");
exit(0);
}
echo "You have CORS!";
}
Security Notes
Check the HTTP_ORIGIN header against a list of approved origins.
If the origin isn't approved, then you should deny the request.
Please read the spec.
TL;DR
When a browser wants to execute a cross-site request it first confirms that this is okay with a "pre-flight" request to the URL. By allowing CORS you are telling the browser that responses from this URL can be shared with other domains.
CORS does not protect your server. CORS attempts to protect your users by telling browsers what the restrictions should be on sharing responses with other domains. Normally this kind of sharing is utterly forbidden, so CORS is a way to poke a hole in the browser's normal security policy. These holes should be as small as possible, so always check the HTTP_ORIGIN against some kind of internal list.
There are some dangers here, especially if the data the URL serves up is normally protected. You are effectively allowing browser content that originated on some other server to read (and possibly manipulate) data on your server.
If you are going to use CORS, please read the protocol carefully (it is quite small) and try to understand what you're doing. A reference URL is given in the code sample for that purpose.
Header security
It has been observed that the HTTP_ORIGIN header is insecure, and that is true. In fact, all HTTP headers are insecure to varying meanings of the term. Unless a header includes a verifiable signature/hmac, or the whole conversation is authenticated via TLS, headers are just "something the browser has told me".
In this case, the browser is saying "an object from domain X wants to get a response from this URL. Is that okay?" The point of CORS is to be able to answer, "yes I'll allow that".
I got the same error, and fixed it with the following PHP in my back-end script:
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST');
header("Access-Control-Allow-Headers: X-Requested-With");
Access-Control-Allow-Headers does not allow * as accepted value, see the Mozilla Documentation here.
Instead of the asterisk, you should send the accepted headers (first X-Requested-With as the error says).
Update:
* is now accepted is Access-Control-Allow-Headers.
According to MDN Web Docs 2021:
The value * only counts as a special wildcard value for requests without credentials (requests without HTTP cookies or HTTP authentication information). In requests with credentials, it is treated as the literal header name * without special semantics. Note that the Authorization header can't be wildcarded and always needs to be listed explicitly.
Many description internet-wide don't mention that specifying Access-Control-Allow-Origin is not enough. Here is a complete example that works for me:
<?php
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, GET, DELETE, PUT, PATCH, OPTIONS');
header('Access-Control-Allow-Headers: token, Content-Type');
header('Access-Control-Max-Age: 1728000');
header('Content-Length: 0');
header('Content-Type: text/plain');
die();
}
header('Access-Control-Allow-Origin: *');
header('Content-Type: application/json');
$ret = [
'result' => 'OK',
];
print json_encode($ret);
I've simply managed to get dropzone and other plugin to work with this fix (angularjs + php backend)
header('Access-Control-Allow-Origin: *');
header("Access-Control-Allow-Credentials: true");
header('Access-Control-Allow-Methods: GET, PUT, POST, DELETE, OPTIONS');
header('Access-Control-Max-Age: 1000');
header('Access-Control-Allow-Headers: Origin, Content-Type, X-Auth-Token , Authorization');
add this in your upload.php or where you would send your request (for example if you have upload.html and you need to attach the files to upload.php, then copy and paste these 4 lines).
Also if you're using CORS plugins/addons in chrome/mozilla be sure to toggle them more than one time,in order for CORS to be enabled
If you want to create a CORS service from PHP, you can use this code as the first step in your file that handles the requests:
// Allow from any origin
if(isset($_SERVER["HTTP_ORIGIN"]))
{
// You can decide if the origin in $_SERVER['HTTP_ORIGIN'] is something you want to allow, or as we do here, just allow all
header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}");
}
else
{
//No HTTP_ORIGIN set, so we allow any. You can disallow if needed here
header("Access-Control-Allow-Origin: *");
}
header("Access-Control-Allow-Credentials: true");
header("Access-Control-Max-Age: 600"); // cache for 10 minutes
if($_SERVER["REQUEST_METHOD"] == "OPTIONS")
{
if (isset($_SERVER["HTTP_ACCESS_CONTROL_REQUEST_METHOD"]))
header("Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE, PUT"); //Make sure you remove those you do not want to support
if (isset($_SERVER["HTTP_ACCESS_CONTROL_REQUEST_HEADERS"]))
header("Access-Control-Allow-Headers: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}");
//Just exit with 200 OK with the above headers for OPTIONS method
exit(0);
}
//From here, handle the request as it is ok
CORS can become a headache, if we do not correctly understand its functioning. I use them in PHP and they work without problems. reference here
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Credentials: true");
header("Access-Control-Max-Age: 1000");
header("Access-Control-Allow-Headers: X-Requested-With, Content-Type, Origin, Cache-Control, Pragma, Authorization, Accept, Accept-Encoding");
header("Access-Control-Allow-Methods: PUT, POST, GET, OPTIONS, DELETE");
This much code works down for me when using angular 4 as the client side and PHP as the server side.
header("Access-Control-Allow-Origin: *");
this should work
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: X-Requested-With, Content-Type, Origin, Cache-Control, Pragma, Authorization, Accept, Accept-Encoding");
I used these 5 headers and after that solved the cors error(backend: PHP, Frontend: VUE JS)
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, PUT, POST, DELETE, OPTIONS, post, get');
header("Access-Control-Max-Age", "3600");
header('Access-Control-Allow-Headers: Origin, Content-Type, X-Auth-Token');
header("Access-Control-Allow-Credentials", "true");
add this code in .htaccess
add custom authentication key's in header like app_key,auth_key..etc
Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Headers: "customKey1,customKey2, headers, Origin, X-Requested-With, Content-Type, Accept, Authorization"