Tornado: how to send back cookies with ajax - ajax

I'm using Tornado to build a web server and Now I'm coding the login module: after doing login, user can send a message to the server.
My idea is as below:
When the user login successfully, the server will set a secure cookie: self.set_secure_cookie("user", username, expires=time.time() + 60).
Then when the user sends a message to the server, the request should contain the cookie that the server just set to tell the server the identity of the user. If there is no cookie in the request, the server will redirect to the login page.
Now the problem is: the server can't get any cookie.
Login:
You can see that a cookie is set when user does login.
Then the browser tries to send a message to the server with ajax:
url: 'http://www.example.com/addcomment',
method: post,
crossDomain: true,
data: message,
processData: false,
cache: false
However, when the server tried to self.get_secure_cookie("user"), it gets a None, which means that the request doesn't send any cookie to the server.
I also add
xhrFields: {
withCredentials: true
},
to the ajax but it doesn't work either.
If ajax can't send any cookie to the server, how could I use the secure cookies of Tornado?

well,after set cookie you can redirect to visit_page_url
self.set_secure_cookie
self.redirect(visit_page_url)
if you via chrome check redirect network request headers,you will find like this have Cookie field:

Related

Using Proxy , Cookies not sent in angular 4 app using withCredentials set to true

I am host angular 4 app on my localhost , Since I need to make api request to my backend which is hosted on web (say https://example.com ) I am using proxy . Here is my proxy config file.
"*": {"target":"https://example.com",
"secure": false,
"logLevel": "debug",
"changeOrigin": true }
So that every request I make goes through the target url . When I make my first request to login page with credentials included I receive cookies in response.But then when I make another request ( POST ) to https://example.com/images I am redirected to the login page . I can see in my network that there are no cookies being sent with the Request headers, however I did receive them from my first login request . I checked out many solutions to this problem. Many of them asked to include {withCredentials=true} in my ajax request which I did in every request.Here is my request
$.ajax({
url: "https://example.com/images",
type: "POST",
crossDomain:true,
headers: {
// includes necessary headers .
},
xhrFields: {
withCredentials: true
},
data:data1 ,
//data1 is json formatted
success: function (res) {
console.log(res)
},
error: function (xhr, status) {
console.log(status);
}
});
But this did not solve the problem. I suspect the cookies are getting lost due to proxy , or the browser is not handling them correctly. I checked I have allowed third party cookies . I need to send those session cookies with this second request . I tried to manually add them but I did not find a way to get and send them along with this request. how can I tackle this issue ? If I remove proxy then I will get the CORS issue . I do not have access to the backend server. hence I tried handling CORS using proxy which works correctly for login request. But this second request is not being sent with cookies. Anyone who can help with this ?
Why are you using jQuery in your angular app, and why use it to do ajax requests, if angular provides an http client?
You better use it and then, use interceptors to add headers to the requests.
When using Angular, do it the Angular way. And use its tools/libraries/patterns.

Ajax saving but not sending CORS cookies from 127.0.0.1 to service

So I've been having issues sending cookies with a cross-domain request to a service. I've gotten to make it work in our CI environment, but not locally. Basically, I have an API at api.service.com, and it's accessed via AJAX calls run from clients at webapp.service.com. The API sets a cookie for .service.com via set-cookie. Then all subsequent calls to the API should include this cookie. This works as intended, when running from webapp.service.com. This will work in prod just fine. However, for obvious reasons, I'd like be able to develop the webapp locally, and run API calls against api.service.com from either local files or localhost service.
I understand that Chrome is a little iffy regarding saving cookies for local files, but I've addressed that, and it is not the issue. The cookie is, in fact, saving. It's just not sending that cookie with subsequent API calls. Here's the workflow I've got going on (with some genericized/censored product names):
An AJAX call POSTS to our API:
$.ajax({
method: "POST",
crossDomain: true,
xhrFields: {
withCredentials: true,
},
url: 'https://api.service.com/login',
data: data,
contentType:"text/plain",
dataType: "json",
success: function(data){
...
}
});
The CORS stuff is set up to allow credentials and this origin (the allowed origin updates dynamically, doesn't use *. So we get this cookie back: cookie:service-token=7f7d251ebeec37f7c0815....; SameSite=lax;Max-Age=2629744; domain=.service.com; path=/;
It shows up in Chrome like this:
Request cookie
I know for a fact that this actually works to save the cookie. However, perhaps not how I want. I go into Chrome's cookies, and it updates properly as seen:
Chrome saved cookie
The problem I'm seeing there is that its "send for" value is "same-site connections only". I have no idea how to originally set that for Chrome to treat it as "any kind of connection." I think this is the reason that, when I send another AJAX call, that cookie is not included in the request.
I've seen other posts like this that were resolved by adding crossDomain and/or withCredentials to the AJAX call. This did not resolve it for me. This is a subsequent call to the API:
$.ajax({
url: 'https://api.service.com/getTheThing',
crossDomain: true,
xhrFields: {
withCredentials: true
},
success: function(data){...}
});
The cookie is not included in this request, and thus fails.
It turns out, setting SameSite=lax was doing the opposite of what I thought it would. Removing that solved this issue.

NodeJS|SailsJS|PassportJS AJAX Authentication: Making Successive Requests for Data

Making Successive Requests for Data
TL;DR
After authentication, I cannot request data from my app's Front-End -- but only through server-side views and Postman can I make subsequent requests for data after logging in, or by authenticating my user in Postman and then making the data request in my app.
First off, I'm a newbie on the server-side.
I've a SailsJS backend which I'm using for REST. Creating and authenticating a user, using LocalStrategy, works fine -- and really, even making subsequent requests for data works fine -- but not via AJAX from my app.
I can use Postman or server-side views to access data, such as /list; making requests after authentication in my app doesn't work -- UNLESS I jump back into Postman and login, then jump back to my app and remake the request.
I do notice that my set-cookie's in my app are different between the first authentication request and the request for /list.
If necessary, I can show some code, but this seems I'm missing a very high-level, basic concept in making authenticated AJAX requests.
EDIT:
My front-end is on a different domain -- Sails runs on localhost:1337 while my UI runs on localhost:8100.
Here's what my /api/config/cors.js looks like:
module.exports.cors = {
allRoutes: true,
origin: '*',
credentials: true,
// methods: 'GET, POST, PUT, DELETE, OPTIONS, HEAD',
// headers: 'content-type'
};
I'm using angular on the front-end, and the subsequent requests are using withCredentials: true -- do I need to add this to the login request too? Must I send the username/email along in the request also?
How do I allow all my subsequent requests for data authenticated after login?
If your frontend application has as a different origin than your backend application the AJAX requests will not include the session cookie by default.
If you are using jQuery:
$.ajax({
url: a_cross_domain_url,
xhrFields: {
withCredentials: true
}
});
This option has to be used for all AJAX requests, so the server can treat them as belonging to the same session.
You also have to configure the server side to allow CORS requests.

Send cookies with ajax call from chrome extension content script

I'm making a chrome extension for a site which provides api to check if user is signed in or not. The api is for a GET request. So when i'm, not singed in it gives.
{ status: "ok", authenticated: false}
When i'm signed in it gives me
{status : "ok", authenticated: true, id: 123}
This works fine on browser, chrome extensions like Postman and advanced Rest Client. But when i use it in my chrome extension background it always says i'm not a authenticated user. I figured out that the ajax call i make does not send cookies for the domain, but the chrome extension like Postman or Advanced REST client do send cookies along with XHR request.
Any idea how can i make ajax to send cookies along with it.
here is my ajax call from chrome extension
$.ajax({
method:"GET",
// xhrFields: {
// withCredentials: true
// },
// crossDomain: true,
url:"http://test-staging.herokuapp.com/user/details",
success: function(result){
if(result.status=="ok"){
alert(JSON.stringify(result));
cb(result.authenticated);
}
},
error: function(err){
alert("unable to authenticate user "+JSON.stringify(err))
}
})
UPDATE 1:
I'm able to get the domain cookies details from the background script. Now i'm looking how i can send the cookies with the ajax call?
If the content script is injected into a page with an origin
(protocol, host and port combination) different from the API origin:
Cookies could be blocked by the third-party cookie blocking feature.
Check if it is enabled: chrome://settings/content/cookies.
Background scripts are not affected by it (as of Chrome 81).
Either set withCredentials: true (credentials: 'include' for fetch)
or add the origin into the permissions section of manifest.json.
To receive the response, correct CORS headers are required in either case.
Prefer moving API calls into a background script and passing data to the
content script with sendMessage to circumvent the third-party cookie blocking,
CORB and CORS restrictions. If you choose to do so, add the API origin into the
permissions section of manifest.json.
This is an old question, but what did it for me had to do with setting a couple flags on my cookies.
According to this blog post: https://www.gmass.co/blog/send-cookie-cross-origin-xmlhttprequest-chrome-extension/
You need to have the samesite: None flag set for this to work. This seems kind of obvious, but wasn't mentioned on most other resources for some reason. In addition, if you want samesite = None, you also need the Secure; flag on the set-cookie: response header so that Chrome will actually listen to it.
For me, and likely for you, this means messing around in your API to have those flags set correctly. For me it even meant I had to make HTTPS work on my localhost server I was developing on, so that chrome would trust me that the cookie was secure. In addition, you need credentials: 'include' as the earlier poster said.
For anyone using flask, this looked like:
app.config['SESSION_COOKIE_SAMESITE'] = "None"
app.config['SESSION_COOKIE_SECURE'] = True
plus debugging with Https (export FLASK_RUN_CERT=adhoc) on the command line.
This is a complex one that took me a long time, but the blog post linked above was a huge help.

CORS $.ajax session cookies (access-control-allow-credentials & withCredentials=true)

I realize this question has been asked a dozen or more times and each response given indicates I am doing it right but perhaps I am missing something.
AJAX serves up CORS request like so...
$.ajax({
url: 'someotherdomain.com',
type: 'post',
data: {key: 'value'},
dataType: 'json',
async: false,
crossDomain: true,
beforeSend: function(xhr){
xhr.withCredentials = true;
},
success: function(x, status, xhr){
},
error: function(xhr, status, error){
}
});
PHP serves up CORS requests like so...
header('Access-Control-Max-Age: 1728000');
header('Access-Control-Allow-Origin: http://someotherdomain.com');
header('Access-Control-Allow-Methods: POST');
header('Access-Control-Allow-Headers: Content-MD5, X-Alt-Referer');
header('Access-Control-Allow-Credentials: true');
header("Content-Type: application/json; charset=utf-8");
According to all documentation as long as the 'Access-Control-Allow-Credentials' server side header, and the 'withCredentials=true' client side header is set session cookie handling between the domains should be transparent. Am I missing something?
async: false
was preventing the session cookie from being sent back to the server on each request. The following fixed it.
async: true
Although this does allow for the session cookie to get set by the browser when making a cross origin request sharing call, I am now experiencing problems regarding the following scenario:
Server A sends response to client
Client using CORS makes request of server B
XMLHttpRequest -> PHP -> Session handler -> MySQL -> Stored Procedure
Due to the MUTEX locks in the PHP session management the asynchronous nature and apparently, requirement may force a work around of manually setting the cookie with a different header option such as XCookie or something similar to keep the servers session and client requests synchronized.
This particular work around does not sit well with me as I believe it would open up an easy lane of travel for session hijacking and session replay attack vectors.
Using an SSL/TLS wrapped connection may assist in preventing the above scenario but in terms of independently providing security measures for the client I do not believe this should suffice.
Anyone with any thoughts on this?
In your example above, you are setting the Access-Control-Allow-Origin header to 'http://someotherdomain.com', which is the same as the url you are requesting from JQuery. The Access-Control-Allow-Origin header should be the value of the domain the request is coming from. As a quick, test, try setting the value of this header to '*' (without the quotes) and see if it works ('*' means all domains are allowed).

Resources