Why is jQuery's .ajax() method not sending my session cookie?
Asked Answered
I

12

386

After logging in via $.ajax() to a site, I am trying to send a second $.ajax() request to that site - but when I check the headers sent using FireBug, there is no session cookie being included in the request.

What am I doing wrong?

Inexpert answered 20/5, 2010 at 0:44 Comment(7)
Cookie of ajax might come after the web cookie and FireBug might catch the first page cookie.Floatation
I did not get what u mean but I can say if I paste the request url in browser address bar and check Firebug again, I can see the cookie in headres sent to the server. Any solutions?Inexpert
So, I think ajax will also handle same way browser doesInexpert
What is the code you're using?Keen
the browser will still create cookies set by the server during a ajax request, jquery or otherwise. Did you check the response to the ajax request and ensure cookies came back from the server to be set? There could be a problem with the server code such that it is not even setting the cookie, etc.Lanfri
to be honest, I had an "issue" like this last week, turns out I was using start_session; instead of start_session(); :(Mcgrew
Your question save my coding life ^^ - I have google search 'flask ajax request has separate session' and it leads me here. Thank you!Singsong
D
241

AJAX calls only send Cookies if the url you're calling is on the same domain as your calling script.

This may be a Cross Domain Problem.

Maybe you tried to call a url from www.domain-a.com while your calling script was on www.domain-b.com (In other words: You made a Cross Domain Call in which case the browser won't sent any cookies to protect your privacy).

In this case your options are:

  • Write a small proxy which resides on domain-b and forwards your requests to domain-a. Your browser will allow you to call the proxy because it's on the same server as the calling script.
    This proxy then can be configured by you to accept a cookie name and value parameter which it can send to domain-a. But for this to work you need to know the cookie's name and value your server on domain-a wants for authentication.
  • If you're fetching JSON objects try to use a JSONP request instead. jQuery supports these. But you need to alter your service on domain-a so that it returns valid JSONP responds.

Glad if that helped even a little bit.

Demoss answered 24/3, 2011 at 16:23 Comment(8)
It's also worth noting that cookies can be set to a specific path so if you cookie was set with path=/something and you are requesting the page /another then the cookie will not be sent. When you request the page /something the cookie will be sent as expected. So check the code that sets the cookie as well.Felisafelise
does a jsonp request send coockies?Johppah
@Johppah Yes, if the requirements I mentioned are set. It's just a normal request like any other and as such sends cookies.Demoss
@Johppah this other related question includes an example of how to do that JSONP request with custom cookiesBullfinch
According to JSONP on Wikipedia > this approach was abandoned in favour of CORSBottle
Does the cookie-sending functionality is only specific to $.ajax() or it will also send the cookies when using vanilla js's ajax request (like XMLHttpRequest)? My understanding is you have to manually set the cookies header while preparing XMLHttpRequest. Please feel free to correct me if I'm wrong?Stimulate
styfle's comment is elaborated in #12755999. The solution 4 given there isn't dependent on Spring.Pantaloon
"The cookie/session info was NOT sent" making my login code stop working. I get stuck for hours without knowing that I'm browsing my web at 0.0.0.0:5000 and making AJAX request to localhost:5000 and thinking they are the same. In fact they are NOT the same! Thank you for saving my coding-lifeSingsong
C
442

I am operating in cross-domain scenario. During login remote server is returning Set-Cookie header along with Access-Control-Allow-Credentials set to true.

The next ajax call to remote server should use this cookie.

CORS's Access-Control-Allow-Credentials is there to allow cross-domain logging. Check https://developer.mozilla.org/En/HTTP_access_control for examples.

For me it seems like a bug in JQuery (or at least feature-to-be in next version).

UPDATE:

  1. Cookies are not set automatically from AJAX response (citation: http://aleembawany.com/2006/11/14/anatomy-of-a-well-designed-ajax-login-experience/)

    Why?

  2. You cannot get value of the cookie from response to set it manually (http://www.w3.org/TR/XMLHttpRequest/#dom-xmlhttprequest-getresponseheader)

    I'm confused..

    There should exist a way to ask jquery.ajax() to set XMLHttpRequest.withCredentials = "true" parameter.

ANSWER: You should use xhrFields param of http://api.jquery.com/jQuery.ajax/

The example in the documentation is:

$.ajax({
   url: a_cross_domain_url,
   xhrFields: {
      withCredentials: true
   }
});

It's important as well that server answers correctly to this request. Copying here great comments from @Frédéric and @Pebbl:

Important note: when responding to a credentialed request, server must specify a domain, and cannot use wild carding. The above example would fail if the header was wildcarded as: Access-Control-Allow-Origin: *

So when the request is:

Origin: http://foo.example
Cookie: pageAccess=2

Server should respond with:

Access-Control-Allow-Origin: http://foo.example
Access-Control-Allow-Credentials: true

[payload]

Otherwise payload won't be returned to script. See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Requests_with_credentials

Chandless answered 25/8, 2011 at 11:22 Comment(6)
Great ! I add to use this + set Access-Control-Allow-Credentials header to true on server sideDispute
and where do I set those Credentials ?, at the Header Autorization ?, at the request body ?Congregational
Thanks for the answer :) just a quick addition, it might be worth mentioning Important note: when responding to a credentialed request, server must specify a domain, and cannot use wild carding. The above example would fail if the header was wildcarded as: Access-Control-Allow-Origin: * developer.mozilla.org/en-US/docs/Web/HTTP/…Homeopathist
None of this worked for me unfortunately. If I run the same request from AngularJS it works, but from jQuery, even with these suggestions the session Cookie is not passed. (jQuery v2.1.1)Deficit
(O.O) You saved me from various painful hours. What a perfect answer! Thanks! I needed to add these in public root .htaccess of my website: <IfModule mod_headers.c> Header set Access-Control-Allow-Origin "localhost" Header set Access-Control-Allow-Credentials "true" </IfModule>Primrosa
I suppose, it is worth mentioning that if you override and provide your own $.ajaxSetup configuration in your code; it is potentially the cause why this might stop working all of a sudden. As others suggested here; then you need to add yourself xhrFields in ajax setup or in your jquery calls. HTH.Every
D
241

AJAX calls only send Cookies if the url you're calling is on the same domain as your calling script.

This may be a Cross Domain Problem.

Maybe you tried to call a url from www.domain-a.com while your calling script was on www.domain-b.com (In other words: You made a Cross Domain Call in which case the browser won't sent any cookies to protect your privacy).

In this case your options are:

  • Write a small proxy which resides on domain-b and forwards your requests to domain-a. Your browser will allow you to call the proxy because it's on the same server as the calling script.
    This proxy then can be configured by you to accept a cookie name and value parameter which it can send to domain-a. But for this to work you need to know the cookie's name and value your server on domain-a wants for authentication.
  • If you're fetching JSON objects try to use a JSONP request instead. jQuery supports these. But you need to alter your service on domain-a so that it returns valid JSONP responds.

Glad if that helped even a little bit.

Demoss answered 24/3, 2011 at 16:23 Comment(8)
It's also worth noting that cookies can be set to a specific path so if you cookie was set with path=/something and you are requesting the page /another then the cookie will not be sent. When you request the page /something the cookie will be sent as expected. So check the code that sets the cookie as well.Felisafelise
does a jsonp request send coockies?Johppah
@Johppah Yes, if the requirements I mentioned are set. It's just a normal request like any other and as such sends cookies.Demoss
@Johppah this other related question includes an example of how to do that JSONP request with custom cookiesBullfinch
According to JSONP on Wikipedia > this approach was abandoned in favour of CORSBottle
Does the cookie-sending functionality is only specific to $.ajax() or it will also send the cookies when using vanilla js's ajax request (like XMLHttpRequest)? My understanding is you have to manually set the cookies header while preparing XMLHttpRequest. Please feel free to correct me if I'm wrong?Stimulate
styfle's comment is elaborated in #12755999. The solution 4 given there isn't dependent on Spring.Pantaloon
"The cookie/session info was NOT sent" making my login code stop working. I get stuck for hours without knowing that I'm browsing my web at 0.0.0.0:5000 and making AJAX request to localhost:5000 and thinking they are the same. In fact they are NOT the same! Thank you for saving my coding-lifeSingsong
S
51

Using

xhrFields: { withCredentials:true }

as part of my jQuery ajax call was only part of the solution. I also needed to have the headers returned in the OPTIONS response from my resource:

Access-Control-Allow-Origin : http://www.wombling.com
Access-Control-Allow-Credentials : true

It was important that only one allowed "origin" was in the response header of the OPTIONS call and not "*". I achieved this by reading the origin from the request and populating it back into the response - probably circumventing the original reason for the restriction, but in my use case the security is not paramount.

I thought it worth explicitly mentioning the requirement for only one origin, as the W3C standard does allow for a space separated list -but Chrome doesn't! http://www.w3.org/TR/cors/#access-control-allow-origin-response-header NB the "in practice" bit.

Spermatium answered 14/5, 2014 at 16:50 Comment(0)
G
45

Put this in your init function:

$.ajaxSetup({
  xhrFields: {
    withCredentials: true
  }
});

It will work.

Grecism answered 19/3, 2015 at 7:8 Comment(2)
You saved my day! On the method level withCredentials didn't work for me. But globaly like this it finally works! Thanks.Tallent
be careful with it, because it will send cookies to all requests, ether for other domains(which is not expect this and fail request by require Access-Control-Allow-Credentials)Guinea
E
16

There are already a lot of good responses to this question, but I thought it may be helpful to clarify the case where you would expect the session cookie to be sent because the cookie domain matches, but it is not getting sent because the AJAX request is being made to a different subdomain. In this case, I have a cookie that is assigned to the *.mydomain.com domain, and I am wanting it to be included in an AJAX request to different.mydomain.com". By default, the cookie does not get sent. You do not need to disable HTTPONLY on the session cookie to resolve this issue. You only need to do what wombling suggested (https://mcmap.net/q/86860/-why-is-jquery-39-s-ajax-method-not-sending-my-session-cookie) and do the following.

1) Add the following to your ajax request.

xhrFields: { withCredentials:true }

2) Add the following to your response headers for resources in the different subdomain.

Access-Control-Allow-Origin : http://original.mydomain.com
Access-Control-Allow-Credentials : true
Eccentricity answered 20/5, 2014 at 23:3 Comment(0)
E
13

After trying out the other solutions and still not getting it to work, I found out what the problem was in my case. I changed contentType from "application/json" to "text/plain".

$.ajax(fullUrl, {
    type: "GET",
    contentType: "text/plain",
    xhrFields: {
         withCredentials: true
    },
    crossDomain: true
});
Eburnation answered 23/2, 2018 at 9:31 Comment(0)
P
4

I was having this same problem and doing some checks my script was just simply not getting the sessionid cookie.

I figured out by looking at the sessionid cookie value in the browser that my framework (Django) was passing the sessionid cookie with HttpOnly as default. This meant that scripts did not have access to the sessionid value and therefore were not passing it along with requests. Kind of ridiculous that HttpOnly would be the default value when so many things use Ajax which would require access restriction.

To fix this I changed a setting (SESSION_COOKIE_HTTPONLY=False) but in other cases it may be a "HttpOnly" flag on the cookie path

Philanthropist answered 12/10, 2013 at 17:16 Comment(2)
Do NOT do this. It allows client side script access to the session cookie which is the most common XSS attack vector. owasp.org/index.php/HttpOnlyFidelity
Even when I do this, the browser won't send the session cookie lmao.Krystenkrystin
H
1

If you are developing on localhost or a port on localhost such as localhost:8080, in addition to the steps described in the answers above, you also need to ensure that you are not passing a domain value in the Set-Cookie header.
You cannot set the domain to localhost in the Set-Cookie header - that's incorrect - just omit the domain.

See Cookies on localhost with explicit domain and Why won't asp.net create cookies in localhost?

Hereinbefore answered 11/7, 2015 at 9:17 Comment(0)
B
0

Just my 2 cents on setting PHPSESSID cookie issue when on localhost and under dev environment. I make the AJAX call to my REST API endpoint on the locahost. Say its address is mysite.localhost/api/member/login/ (virtal host on my dev environment).

  • When I do this request on Postman, things go fine and PHPSESSID is set with the response.

  • When I request this endpoint via AJAX from the Browsersync proxied page (e.g. from 122.133.1.110:3000/test/api/login.php in my browser address line, see the domain is different vs mysite.localhost) PHPSESSID does not appear among cookies.

  • When I make this request directly from the page on the same domain (i.e. mysite.localhost/test/api/login.php) PHPSESSID is set just fine.

So this is a cross-origin origin request cookies issue as mentioned in @flu answer above

Blaney answered 15/11, 2018 at 9:32 Comment(0)
C
0

Adding my scenario and solution in case it helps someone else. I encountered similar case when using RESTful APIs. My Web server hosting HTML/Script/CSS files and Application Server exposing APIs were hosted on same domain. However the path was different.

web server - mydomain/webpages/abc.html

used abc.js which set cookie named mycookie

app server - mydomain/webapis/servicename.

to which api calls were made

I was expecting the cookie in mydomain/webapis/servicename and tried reading it but it was not being sent. After reading comment from the answer, I checked in browser's development tool that mycookie's path was set to "/webpages" and hence not available in service call to

mydomain/webapis/servicename

So While setting cookie from jquery, this is what I did -

$.cookie("mycookie","mayvalue",{**path:'/'**});
Cryometer answered 10/9, 2019 at 14:36 Comment(0)
P
0

This errors occurs when you try to send cross site request. How I solve this problem?

In nginx configuration file I added

add_header Access-Control-Allow-Origin '*.domain.com'
add_header Access-Control-Allow-Credentials 'true';

And in the 'domain.com' I'm trying to send ajax request with

$.ajax({
   url: sub.domain.com,
   xhrFields: {
      withCredentials: true
   }
});
Paronomasia answered 15/8, 2022 at 9:49 Comment(0)
C
-5

Perhaps not 100% answering the question, but i stumbled onto this thread in the hope of solving a session problem when ajax-posting a fileupload from the assetmanager of the innovastudio editor. Eventually the solution was simple: they have a flash-uploader. Disabling that (setting

var flashUpload = false;   

in asset.php) and the lights started blinking again.

As these problems can be very hard to debug i found that putting something like the following in the upload handler will set you (well, me in this case) on the right track:

$sn=session_name();
error_log("session_name: $sn ");

if(isset($_GET[$sn])) error_log("session as GET param");
if(isset($_POST[$sn])) error_log("session as POST param");
if(isset($_COOKIE[$sn])) error_log("session as Cookie");
if(isset($PHPSESSID)) error_log("session as Global");

A dive into the log and I quickly spotted the missing session, where no cookie was sent.

Complaisance answered 4/8, 2014 at 22:5 Comment(2)
I don't think the example above would work, because when there's no session cookie, what would the value of $sn be? (a random one, or maybe null), alternatively users could set session_name from a GET value for example session_name(isset($_GET['sess']) ? $_GET['sess'] : null);session_start(); this way, they'd get a working thingMiddleoftheroad
That is exactly how i found the problem: no session when posting from this flash uploader thingy. As using a GET variable session identifier is a bad idea, and the cookie was not working, i threw it out. Who cares, flash is a thing of the past anyways.Complaisance

© 2022 - 2024 — McMap. All rights reserved.