I am having a terrible time trying to get my server to accept requests from another server (local, but given a domain name in my hosts file) without triggering the dreaded
XMLHttpRequest cannot load https://dev.mydomain.org/api/user?uid=1. Origin http://home.domain.org is not allowed by Access-Control-Allow-Origin.
my dev server (internet) is running nginx, my home server(local) is running apache.
I have tried several solutions found on the internet, to no avail. I have tried modifying the headers in the nginx configs to allow my home.mydomain.org server, I have also added htaccess rules locally to allow all origins (*).
My nginx server block has these lines currently:
add_header Access-Control-Allow-Origin http://home.mydomain.org;
add_header Access-Control-Allow-Headers Authorization;
Adding just the first one did change my response slightly (from simple Origin not allowed by Access-Control-Allow-Origin
to Request header field Authorization is not allowed by Access-Control-Allow-Headers.
) but adding the second line just reverted the error to the original one and I am still blocked.
At this point, I am not sure what else to try.
UPDATES:
Launching Chrome with flag --disable-web-security allows me to test, and my site and code is working fine in Chrome.
However, this revealed another strange problem, which is that if I try adding the add_header lines to a location directive, both my no-web-security Chrome and my unmodified Safari fail to load info from my api. So now I am not sure if my add_header directives in the server block are working correctly at all.
If it helps any, here is my client code (including things I have tried/commented out):
var xhr = new XMLHttpRequest();
var self = this;
xhr.open('GET', apiURL + self.currentIssue);
xhr.setRequestHeader('Access-Control-Allow-Origin','http://home.mydomain.org');
//xhr.setRequestHeader('Access-Control-Allow-Credentials', 'true');
xhr.withCredentials = true;
//xhr.setRequestHeader('Access-Control-Request-Method','*');
xhr.setRequestHeader('Authorization','Bearer longstringoflettersandnumbers');
xhr.onload = function () {
self.posts = JSON.parse(xhr.responseText);
};
xhr.send();
ANOTHER UPDATE AFTER TRYING SUGGESTION BELOW: After a bunch of trial and error on both client and server, I still am stuck. Here is my latest response from the server using curl (although I have toggled on and off various options client and server for things like Credentials and changing origin to exactly mine or * to no avail):
HTTP/1.1 204 No Content
Server: nginx
Date: Sun, 06 Aug 2017 10:11:57 GMT
Connection: keep-alive
Access-Control-Allow-Origin: http://home.mydomain.org
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: Authorization,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range
Access-Control-Max-Age: 1728000
Content-Type: text/plain; charset=utf-8
Content-Length: 0
and here are my console errors (Safari):
[Error] Origin http://home.mydomain.org is not allowed by Access-Control-Allow-Origin.
[Error] Failed to load resource: Origin http://home.mydomain.org is not allowed by Access-Control-Allow-Origin. (actions, line 0)
[Error] XMLHttpRequest cannot load https://dev.mydomain.org/api/user?uid=1 due to access control checks.
And here is my console error for Firefox:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://dev.mydomain.org/api/user?uid=1. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing).
Also in Firefox, here are the results from the network panel for OPTIONS and GET:
Request URL: https://dev.mydomain.org/api/user?uid=1
Request method: OPTIONS
Status code: 204 No Content
Version: HTTP/2.0
Response headers (511 B)
Server "nginx"
Date "Sun, 06 Aug 2017 10:44:22 GMT"
Access-Control-Allow-Origin "http://home.mydomain.org"
access-control-allow-credentials "true"
Access-Control-Allow-Methods "GET, POST, OPTIONS"
Access-Control-Allow-Headers "Authorization,DNT,X-CustomHea…ent-Type,Content-Range,Range"
Access-Control-Max-Age "1728000"
Content-Type "text/plain; charset=utf-8"
Content-Length "0"
X-Firefox-Spdy "h2"
Request headers (501 B)
Host "dev.mydomain.org"
User-Agent "Mozilla/5.0 (Macintosh; Intel… Gecko/20100101 Firefox/54.0"
Accept "text/html,application/xhtml+x…lication/xml;q=0.9,*/*;q=0.8"
Accept-Language "en-US,en;q=0.5"
Accept-Encoding "gzip, deflate, br"
Access-Control-Request-Method "GET"
Access-Control-Request-Headers "authorization"
Origin "http://home.mydomain.org"
Connection "keep-alive"
Cache-Control "max-age=0"
Request URL: https://dev.mydomain.org/api/user?uid=1
Request method: GET
Status code: 404 Not Found
Version: HTTP/2.0
Response headers (170 B)
Server "nginx"
Date "Sun, 06 Aug 2017 10:44:22 GMT"
Content-Type "text/html"
Vary "Accept-Encoding"
Content-Encoding "gzip"
X-Firefox-Spdy "h2"
Request headers (723 B)
Host "dev.mydomain.org"
User-Agent "Mozilla/5.0 (Macintosh; Intel… Gecko/20100101 Firefox/54.0"
Accept "*/*"
Accept-Language "en-US,en;q=0.5"
Accept-Encoding "gzip, deflate, br"
Referer "http://home.mydomain.org/"
Authorization "Bearer eyJ0eXAG…BRHmX9VmtYHQOvH7k-Y32wwyeCdk"
Origin "http://home.mydomain.org"
Connection "keep-alive"
Cache-Control "max-age=0"
UPDATE WITH PARTIAL SUCESS:
I think I found the problem (partially): changing my location directive in nginx from location /api
to location = /api/*
gets it working! But only for Safari and Chrome, FF is now not even trying the GET request, there is NO entry for it in network panel.
UPDATE WITH CRYING AND GNASHING OF TEETH AND PULLING OF HAIR Safari and Chrome intermittently fail with original error about Origin not allowed, even though they were working fine and no changes have been made to server config. I will be drinking heavily tonight...
Wow, was that ever convoluted. Posting answer here in case some other WP user finds their way here. I kept getting inconsistent results (sometimes working, sometimes not mysteriously) and finally tracked down my problem to headers being set in the PHP code on the server, independently of the nginx settings and sometimes contradicting them (although never in a predictable way that I could see). So the things I needed to resolve were:
!$_SERVER['REQUEST_METHOD'] === "OPTIONS"
)rest_pre_serve_request
My filter code is here:
add_action('rest_api_init', function() {
/* unhook default function */
remove_filter('rest_pre_serve_request', 'rest_send_cors_headers');
/* then add your own filter */
add_filter('rest_pre_serve_request', function( $value ) {
$origin = get_http_origin();
$my_sites = array( $origin ); // add array of accepted sites if you prefer
if ( in_array( $origin, $my_sites ) ) {
header( 'Access-Control-Allow-Origin: ' . esc_url_raw( $origin ) );
} else {
header( 'Access-Control-Allow-Origin: ' . esc_url_raw( site_url() ) );
}
header( 'Access-Control-Allow-Methods: OPTIONS, GET, POST, PUT, PATCH, DELETE' );
header( 'Access-Control-Allow-Credentials: true' );
header('Access-Control-Allow-Headers: Authorization,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Origin,Content-Type,X-Auth-Token,Content-Range,Range');
header('Access-Control-Expose-Headers: Authorization,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Origin,Content-Type,X-Auth-Token,Content-Range,Range');
header( 'Vary: Origin' );
return $value;
});
}, 15);
Now finally, everything works everywhere (in every browser and in curl too)!