Reputation: 333
I have built an API that generates an authentication token for the users that log in. At this time I also have a client application written in Node.JS.
When I make the request with the user credentials from the client application to the API I get the authentication token: how should I store it in the client application? I'm not supposed to request a token every time I want to make a request for the API, correct?
I thought about putting the token in a Cookie, but I don't think that's the best solution.
What would you recommend?
Upvotes: 15
Views: 12577
Reputation: 7306
We're working on an application that uses a very similar approach. The client application is a static HTML5/JS single-page application (with no server-side generation whatsoever) and communicates with an API server.
The best approach is to store the session token in memory: that is, inside a variable in the JS code. If your client application is a single page, it shouldn't be a problem.
In addition to that, we also keep the session token in sessionStorage to preserve it in case the user refreshes the page. To preserve the token when new tabs are created (sessionStorage is specific to a browser window), we also store it in localStorage when the page is being closed, together with a counter for open tabs (when all tabs of the application are closed, we remove the token.
// Handle page reloads using sessionStorage
var sess = sessionStorage.getItem('session-token')
if(sess && sess !== 'null') { // Sometimes empty values are a string "null"
localStorage.setItem('session-token', sess)
}
// Set a counter to check when all pages/tabs of the application are closed
var counter = parseInt(localStorage.getItem('session-counter') || 0, 10)
counter++
localStorage.setItem('session-counter', counter)
// Event fired when the page/tab is closing
window.onbeforeunload = function() {
var counter = parseInt(localStorage.getItem('session-counter') || 0, 10)
counter--
localStorage.setItem('session-counter', counter)
// All pages are closed: remove the session token
if(counter <= 0) {
// Handle page reloads using sessionStorage
sessionStorage.setItem('session-token', localStorage.getItem('session-token'))
localStorage.removeItem('session-token')
}
}
For more information about localStorage and sessionStorage: https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API
Why not cookies? Cookies are bad for two reasons: 1. They are generally more persistent, being shared across browser windows and tabs, and they can persist even after the browser is closed. 2. Most importantly, however, by the HTTP specifications they must be sent to the web server every time a request is made. If you're designing an application where the client is completely separated from the API server, you don't want the client's server to see (or log!) the session token in any case.
Some extra advices:
Upvotes: 1
Reputation: 202176
I think that this link could help you:
In fact, you should have a token with an expiration date, so you don't have to get a new token each time before sending a request. When the token expires, you simply need to get a new one from a service "refresh token".
Regarding the question about how to store the token in the client application, I think that you could keep it in memory (map or embedded database).
Otherwise to finish, I don't think that it's a good idea to use cookies in such use case.
Hope it will help you. Thierry
Upvotes: 1
Reputation: 288
Upon successful login, a unique, one-use token should be created server side and stored in the database against a user id and timestamp. You store the token in a cookie client-side. You then pass the token up to every subsequent API call. The server should then check the token is valid (ie not expired, say issued or update less then say 30 minutes ago). If it is valid, you can retrieve the user details stored against that token and perform whatever backend functionality you need (as the user is authenticated). You then update the timestamp for that token (refresh the session as you want the login to time out after say 30 minutes of no user interaction). If a token is expired or non-existent when you get the API call, redirect to the login page.
Also, you probably know this already, but make sure the token is unique and non-guessable, I tend to generate new random GUIDs and encrypt them, do not use sequentail ids or anything like that.
Upvotes: 11