Sending credentials with cross-domain posts?
Functionality is supposed to be broken in jQuery 1.5.
Since jQuery 1.5.1 you should use xhrFields param.
$.ajaxSetup({
type: "POST",
data: {},
dataType: 'json',
xhrFields: {
withCredentials: true
},
crossDomain: true
});
Docs: http://api.jquery.com/jQuery.ajax/
Reported bug: http://bugs.jquery.com/ticket/8146
Cross domain jQuery ajax call with credentials
My best guess is that this is a problem not with your Javascript but with your CORS configuration. Did you set up your server with the Access-Control-Allow-Credentials: true
header? http://www.w3.org/TR/cors/#access-control-allow-credentials-response-header
Also note that, even when the allow-credentials header is set, the browser will not allow responses to credentialed requests if Access-Control-Allow-Origin
is *, according to these docs: https://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS?redirectlocale=en-US&redirectslug=HTTP_access_control#Requests_with_credentials.
Edit: Since the OP has the CORS headers set up properly, the problem seems to be that the server is rejecting OPTIONS requests with a 403 status code. OPTIONS requests (known as the "preflight request") are sent before certain cross-domain requests (such as POSTs with application/xml content types), to allow the server to notify the browser of what types of requests are allowed. Since the browser doesn't see the 200 response that it expects from the OPTIONS request, it doesn't fire the actual POST request.
JQuery $.post cross domain and credentials
You can use jQuery.ajaxSetup() to set default options that each ajax request will use (including $.post
and $.get
)
$.ajaxSetup({
crossDomain: true,
xhrFields: {
withCredentials: true
},
username: 'test',
password: 'test'
});
$.post('http://example.com/server/api.php', {
username: 'test',
password: 'test'
}, function (d) {
$('body').html(d.status);
}, 'json');
Also the warning regarding this API
Note: The settings specified here will affect all calls to $.ajax or
Ajax-based derivatives such as $.get(). This can cause undesirable
behavior since other callers (for example, plugins) may be expecting
the normal default settings. For that reason we strongly recommend
against using this API. Instead, set the options explicitly in the
call or define a simple plugin to do so.
from jQuery documentation
Set cookies for cross origin requests
Cross site approach
To allow receiving & sending cookies by a CORS request successfully, do the following.
Back-end (server) HTTP header settings:
Set the HTTP header
Access-Control-Allow-Credentials
value totrue
.Make sure the HTTP headers
Access-Control-Allow-Origin
andAccess-Control-Allow-Headers
are set. Don't use a wildcard*
. When you set the allowed origin make sure to use the entire origin including the scheme, i.e. http is not same as https in CORS.
For more info on setting CORS in express js read the docs here.
Cookie settings:
Cookie settings per Chrome and Firefox update in 2021:
SameSite=None
Secure
When doing SameSite=None
, setting Secure
is a requirement. See docs on SameSite and on requirement of Secure. Also note that Chrome devtools now have improved filtering and highlighting of problems with cookies in the Network tab and Application tab.
Front-end (client): Set the XMLHttpRequest.withCredentials
flag to true
, this can be achieved in different ways depending on the request-response library used:
ES6 fetch() This is the preferred method for HTTP. Use
credentials: 'include'
.jQuery 1.5.1 Mentioned for legacy purposes. Use
xhrFields: { withCredentials: true }
.axios As an example of a popular NPM library. Use
withCredentials: true
.
Proxy approach
Avoid having to do cross site (CORS) stuff altogether. You can achieve this with a proxy. Simply send all traffic to the same top level domain name and route using DNS (subdomain) and/or load balancing. With Nginx this is relatively little effort.
This approach is a perfect marriage with JAMStack. JAMStack dictates API and Webapp code to be completely decoupled by design. More and more users block 3rd party cookies. If API and Webapp can easily be served on the same host, the 3rd party problem (cross site / CORS) dissolves. Read about JAMStack here or here.
Sidenote
It turned out that Chrome won't set the cookie if the domain contains a port. Setting it for localhost
(without port) is not a problem. Many thanks to Erwin for this tip!
Cross Origin Resource Sharing with Credentials
Two thoughts:
1) are you also including the "Access-Control-Allow-Credentials: true" header? This is needed for passing cookie credentials (and the corresponding XHR client must set .withCredentials = true)
2) Have you tried the suggestion from your link and only include the origin for the current request. For example, if a request comes in with the header "Origin: http://blog.example.com", you would respond with "Access-Control-Allow-Origin: http://blog.example.com", and not a list of origins. This requires a little more work on your server side implementation.
3) One other thought, you mention that you have a single login form that must be shared by various domains. Well, if it is a standard HTML form, you can do a regular form-post across domains. You don't need to use CORS. Just set the "action" property of the form to the url you wish to post to. For example:
<form name="login" action="http://login.example.com/doLogin">
How to make XMLHttpRequest cross-domain withCredentials, HTTP Authorization (CORS)?
I've written an article with a complete CORS setup.
I found several issues that can result in this problem:
- The
Access-Control-Allow-Origin
cannot be a wildcard if credentials are being used. It's easiest just to copy theOrigin
header of the request to this field. It's entirely unclear why the standard would disallow a wildcard. - Firefox caches the Access-Control results even if you clear the cache (perhaps for the session). Restarting forced it to do a new
OPTIONS
request. To aid in debugging I added the headerAccess-Control-Max-Age: 1
- The username/password of the
open
command is apparently not usable as the credentials. You must add anAuthorization
header yourself.xhr.setRequestHeader( 'Authorization', 'Basic ' + btoa( user + ':' + pass ) )
Overall the withCredentials
system is rather braindead. It's easier to simply write a server that accepts the authorization as part of the body of the request.
Related Topics
Nodejs Callbacks Simple Example
Activexobject in Firefox or Chrome (Not Ie!)
How Does Variable Assignment Work in JavaScript
Convert a Binary Nodejs Buffer to JavaScript Arraybuffer
How to Parse JSON to Receive a Date Object in JavaScript
How to Process Each Letter of Text Using JavaScript
Removeeventlistener on Anonymous Functions in JavaScript
What Is the Order of Execution in JavaScript Promises
Check If Event Exists on Element
JavaScript - Get Minutes Between Two Dates
Make Several Requests to an API That Can Only Handle 20 Request a Minute
How to Dynamically Insert a <Script> Tag via Jquery After Page Load
How to Get Notified About Changes of the History via History.Pushstate