Backbone and cookies / sessions - javascript

I have configured jquery to include the cookie header with each request:
$.ajaxSetup({
cache: false,
xhrFields: {
withCredentials: true
}
});
On the server-side, I run Node with Express.
Sessions are managed with the express-sessions middleware and the Mongostore plugin.
Before adding the xhrFields configuration, I noticed that for each request, a new session was stored in the database.
I inspected the request headers and noticed that no cookie header was present.
After configuring ajax as above, I notice that still there are too many sessions stored on the server-side.
The problem is the OPTIONS request emitted by Backbone.
I checked the headers of this request and there is no session information included in these requests. Since no Session id is sent to the server, the server creates and stores a new one. It also tries to set a new cookie on the client, which will change the client's session id.
I see two options:
Configure ajax somehow to send the cookie info on ALL requests.
Disable the session middleware on the option routes (which means I will have to include the middleware on all routes that require the session and NOT include it in all other routes).
I will implement the latter. But maybe there is a better solution?

Related

JWT token with AJAX, non-AJAX, JQuery

I'm a bit frustrated with managing my JWT token during login, submits and redirects. Before I get started here's my technology stack just in case:
JQuery/Html -> Node.Js -> Java Restful Services -> MySQL.
My java Restful services manages creating the JWT Token returning it to the Node.js layer which decides what to do with it and pass it on the the client. This all works wonderfully.
To get the JWT token I'm making an ajax based authentication request to the Node middle tier, which authenticates and returns the token which is summarily crammed into localstorage on the client.
Now I have no desire what so ever to make the entire site load off a single page through ajax, it's a complex site and doing that is just dumb! I need to forward and navigate to sub pages while carrying along the JWT token.
Here's the question (finally)... How do send along the JWT token to the middle tier (node.js) without attaching it as a request or post parameter because that's a big no no? I can't seem to find a way to stuff it in the header associated with Bearer.
You need to store the token at client side using for example a cookie or localStorage
Ajax requests
Cookies: A cookie is sent automatically when making a request to the server, so you do not need to add a specific header
LocalStorage:It is needed to provide the token in each request using an HTTP header.
For example
POST /authenticatedService
Host: example.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
This is an example code to show how to execute an ajax POST request using jquery
$.ajax({
type: "POST", //GET, POST, PUT
url: '/authenticatedService' //the url to call
data: yourData, //Data sent to server
contentType: contentType,
beforeSend: function (xhr) { //Include the bearer token in header
xhr.setRequestHeader("Authorization", 'Bearer '+ jwt);
}
}).done(function (response) {
//Response ok. process reuslt
}).fail(function (err) {
//Error during request
});
Form submit
With a form submission you can not control the headers set by browser, so it is not possible to set the Authorization header with a Bearer token. In this case you can
Cookie: store the JWT in a cookie that will be sent with the form data. You will need to add extra security to avoid CSRF attachs
Form param: The JWT is stored in a hidden field of the form.
Use always POST (not GET) to avoid cache of JWT
Link
A link executes a GET request. You could build the link adding the JWT as a query param url?jwt=...
But, consider in this case the security risks. Browser can cache the url and it will be present in logs. An attacker could potentially obtain them if he has access. Also the user could copy the link and use it outside your web application (e.g send it by email...)
If you use cookies, the token will be automatically sent to the server by clicking on the link, but this will only work if the user is authenticated. In this case be aware of CSRF vulnerabilities
Your only option is to store the token in a cookie if you don't want to do anything suggested above. You can't set http headers in links.

What is the best way to access the JWT from node?

I have implemented JWT authentication using Node.js. When the user signs in, Node.js signs/creates a JWT and sends it back. Thereafter, it is stored in the localStorage. Now, this is probably where I am going wrong, but... to move forward, I make use of the express router, and within the router code (which is obviously at the node level) I want to be able to access the token (which is in localStorage) so that I can make a call to the API for further data. However, I just realised that localStorage is at the client-end and that node/express/router doesn't recognise localStorage. So I am stuck. Obviously, I am doing something fundamentally wrong... I should not need to access localStorage from the express router file. Perhaps, I should really be making the API calls not from the express router file, but from client side.
Any hints/directions?
localstorage is bad way to save token. you should save token in cookies and use then where you want.
EXAMPLE:
new Cookies(req,res).set('access_token',token,{
httpOnly: true,
secure: true // for your production environment
});
and then read:
var token = new Cookies(req,res).get('access_token');
You need to send the JWT that is stored on the client side every time you make an API request to the server side.
https://jwt.io/introduction/
Scroll down to the section How do JSON Web Tokens work? The JWT should be sent in the header of the API calls in the form:
Authorization: Bearer <token>
How you do this depends on how exactly you'll send the HTTP requests to the API, but it should be pretty simple in any respects. You can find out about how to add Headers to an angular $http request at this link:
https://docs.angularjs.org/api/ng/service/$http
Then it's up for each of your authenticated express routes to check the headers, pull the JWT out, ensure that it's valid, and then proceed with the request (or halt it if the JWT is invalid).

Do I have to make a script to make an authorization header for jwt?

I am working on a simple website using jwt. (node.js, koa.js)
Most example codes including expressjs, I cannot find the client-side example
about how to deal with jwt sent from a server.
Only one example (https://github.com/auth0-blog/cookie-jwt-auth) showed me that
[index.html]
... script src="app.js...
[app.js]
$.ajax({
type: 'POST',
url: 'http://localhost:3001/secured/authorize-cookie',
data: {
token: token
},
headers: {
'Authorization' : 'Bearer ' + token
}
After I read this example, I felt that I should have some scripts for users to send an authorization header with jwt. Is it right?
Or are there some front-end frameworks that deal with authorization header?
Thank you for reading newbie'q question.
Yes, you will need to define a mechanism for sending the user's JWT back to the server. It's up to you to decide where the JWT will live in the request -- the most common places are in the Authorization header, or by setting a cookie on the browser (which will be sent along with every HTTP request). You should also consider whether you want the JWT to persist across sessions / page reloads (using for example document.cookie or localStorage).
If you choose not to use the cookie approach, you can configure all $.ajax requests to set your Authorization header "pre-flight" using $.ajaxSetup({...}) (but this is a bit of a sledge-hammer approach). Manually setting the Authorization header on each individual $.ajax request, as you've demonstrated above, is a good option too.
If you want to skip headers all together, you can send the JWT inside the body of your request (as JSON, for example).

Javascript: remove a cookie that was set by an ajax response

in my Webapp (that is running at localhost/myApp/), I have an ajax call like:
$.ajax({
type: "GET",
url: "http://localhost:8080/my.module/Login/login?user=abc&password=123",
xhrFields: {
withCredentials: true,
},
success: onResult,
error: onError,
});
to login on the server. The server responds with a boolean value if the login was successful and the response also contains this header:
Set-Cookie: JSESSIONID=167C57FA1E3529433938E744F7C4AC52; Path=/my.module
With the previously set xhrField "withCredentials: true", the browser automatically handles the cookie and appends the Cookie header in all following requests:
Cookie: JSESSIONID=167C57FA1E3529433938E744F7C4AC52
This works perfectly fine. But now I have the problem, that the server has a bug so it doesn't remove a session when calling the logout interface, a session can't be closed (and I don't have access to the server). In order to logout properly I would have to remove the session cookie on the client so I would get a new one from the server. But i can't find a way to access or remove the cookie, the document.cookie variable is empty in my webapp. I also tried to read the document.cookie variable from localhost/myApp/my.module/ and localhost/my.module/, but it is always empty. Another thing i tried was overwriting the cookie with
document.cookie = "JSESSIONID=ABC; Path=/my.module";
but the server requests still have the cookie from before. Can anyone tell me how i could remove it?
I know this solution would be a hack, but that's what I'm looking for, because the server programmers can't fix the bug in time and asked me to implement such a hack on the client.
"An HttpOnly cookie is not accessible via non-HTTP methods, such as calls via JavaScript " -http://en.wikipedia.org/wiki/HTTP_cookie#Secure_and_HttpOnly
First of all, the client javascript shouldn't care about the cookie.
When the server sees a login request, it creates a new cookie and calls Set-Cookie.
On receiving any other ajax request, server validates the current cookie, before serving the request.
On logout request, it will clear the cookie from its (server's) session info i.e. any further requests from the client with the same cookie will fail since its not in the server store.

Set-Cookie in HTTP header is ignored with AngularJS

I'm working on an application based on AngularJS on client side and Java for my API (Tomcat + Jersey for WS) on server side.
Some path of my API are restricted, if the user doesn't have a session the response status returned is 401. On the client side, 401 http status are intercepted to redirect the user to the login page.
Once the user is authenticated, I create a session on the server side httpRequest.getSession(true);
and the response send to the client does have the Set-cookie instruction in its header :
Set-Cookie:JSESSIONID=XXXXXXXXXXXXXXXXXXXXX; Domain=localhost; Path=/api/; HttpOnly
The problem is that the cookie is never put on the client side. When I inspect cookie for localhost domain it's empty, so the next requests don't have this cookie in their header and client side still couldn't access to the restricted path of my API.
The client and the server are on the same domain but they don't have the same path and the same port number :
Client : http://localhost:8000/app/index.html
Server : http://localhost:8080/api/restricted/
Additional info : CORS is enabled on the both side :
"Access-Control-Allow-Methods", "GET, POST, OPTIONS"
"Access-Control-Allow-Origin", "*"
"Access-Control-Allow-Credentials", true
Any idea for making the Set-cookie works properly ?
Is it an AngularJS related issue ?
I found an issue in AngularJS that help me to move forward.
It seems that "Access-Control-Allow-Credentials" : true was not set on the client side.
Instruction $httpProvider.defaults.withCredentials = true was ignored.
I replace $resource call by a simple $http call with {withCredentials:true} in the config parameter.
I've managed to solve an issue very similar to yours.
My Play! backend tried to set a session Cookie which I could not catch in Angular or store via browser.
Actually the solution involved a bit of this and a bit of that.
Assuming you've solved the initial issue, which can be solved only by adding a specific domain to the Access-Control-Allow-Origin and removing the wildcard, the next steps are:
You have to remove the HTTP-Only from the Set-Cookie header, otherwise you will never be able to receive a cookie "generated" by your angular code
This setup will already work in Firefox, though not in Chrome
To make it work for Chrome too, you need to:
a) send a different domain from localhost in the cookie, using the domain your WS are "hosted". You can even use wildcards like .domain.com instead of ws.domain.com
b) then you'll need to make a call to the domain you specified in the cookie, otherwise Chrome won't store your cookie
[optional] I would remove that /api path in favor of a /
And that should to the trick.
Hope to have been of some help
In your post request on the client side, make sure to add the following:
For jquery ajax requests:
$.ajax({
url: "http://yoururlgoeshere",
type: "post",
data: "somedata",
xhrFields: {
withCredentials: true
}
});
With Angular's $http service :
$http.post("http://yoururlgoeshere", "somedata", {
withCredentials: true
});
You need work on both the server and client side.
Client
Set $http config withCredentials to true in one of the following ways:
Per request
var config = {withCredentials: true};
$http.post(url, config);
For all requests
angular.module("your_module_name").config(['$httpProvider',
function($httpProvider) {
$httpProvider.interceptors.push(['$q',
function($q) {
return {
request: function(config) {
config.withCredentials = true;
return config;
}
};
}
]);
}
]);
Server
Set the response header Access-Control-Allow-Credentials to true.
The addition HttpOnly means that the browser should not let plugins and JavaScript see the cookie. This is a recent convention for securer browsing. Should be used for J_SESSIONID but maybe not here.
Just solved a problem like this.
I was doing this and not working...:
$cookies.put('JSESSIONID', response.data);
Cookies are saved in the browser, but when I sent a new request, all the cookies were sent exept mine. (my cookie is JSESSIONID)
then i look in the chrome inspector and i found this:
THE PROBLEM IS THAT WAS NOT THE CORRECT PATH!!!
then I tried this and my cookies were sent. yay! :
$cookies.put('JSESSIONID', response.data, {'path':'/'});
I do not know if this is your case, but this worked for me.
regards!

Categories

Resources