Every web application in the world that maintains user data has to deal with sessions. As developers, we need to know what they are and how to use them.
In this article, I want to share:
- What is a session?
- How do sessions store data?
- How do you determine where to keep your session data?
- What security implications do you have to be aware of when working with sessions?
For some of the code examples, I’ll be leveraging the session npm module, which is probably the most common session library out there.
What is a session?
A session is a place to store data that you want access to across requests. Each user that visits your website has a unique session. You can use sessions to store and access user data as they browse your application.
Sessions are integral to web application development because they allow the application to store state. Based on what action a user took on Page A, we can show a different Page B. Without them, applications would be stateless, and not very useful.
Here’s how you can set up a simple session in Express:
import express from 'express'; import session from 'express-session'; var app = express(); app.use(session());
If your application has enabled sessions, you can set some data in one route handler:
app.use(session({ secret: 'this-is-a-secret-token', cookie: { maxAge: 60000 }})); // Access the session as req.session app.get('/', function(req, res, next) { var sessData = req.session; sessData.someAttribute = "foo"; res.send('Returning with some text'); });
And read it in another route handler:
app.get('/bar', function(req, res, next) {
var someAttribute = req.session.someAttribute;
res.send(This will print the attribute I set earlier: ${someAttribute}
);
});
Sessions can store their information in different ways. The popular ways to store session data is:
- In application memory
- In a cookie
- In a memory cache
- In a database
Storing Session Data in Application Memory
One way to store session data is in Application memory. This is often the simplest way, but not used in production.
Storing session data in application memory essentially means that the data is stored for the lifetime of your application runtime. If your web application server crashes or is stopped, all session data is removed.
Storing session data in memory also causes memory leaks. As your application stays running, more and more memory is used, until your app runs out of memory.
For development purposes, it is often useful to store sessions in application memory. Otherwise, there are better ways of storing session data. We’ll explore these below.
Storing Session Data in Cookies
A cookie is usually a small piece of data that gets sent between a web server to your web browser. It allows the server to store information relevant to a specific user.
One common use for cookies is to store session data. This works in the following way.
- The server issues a cookie that gets sent to the web browser and stored for a period of time (called the expiration time).
- When a user makes a subsequent request to the web server, this cookie gets sent along with the request, and the server can read the information that is in it.
- The server can manipulate the cookie if it needs to, and then sends it back to the browser.
Until the cookie expires, every time you make a request, your browser will send the cookies back to the server.
A module like express-session will provide you with a nice API to work with sessions (letting you get & set data to the session), but under the hood, it will save and retrieve this data using a cookie.
Express-session also offers ways to secure your cookies. We won’t get into the security details here, but I recommend reading the documentation to read up on the security options. It is essential to ensure that the information inside your application cookies are not exposed.
This brings up some other issues with cookies:
- They can only store small bits of data, about 4KB usually.
- They are sent in every request, and if you store a bunch of data in a cookie, it will increase the size of the requests, which will slow down your site’s performance.
- If an attacker figures out how your cookies are encrypted (your secret key), then your cookies will be compromised. Attackers will then be able to read the data that is stored in the cookies, which can be sensitive user data.
Storing Session Data in a Memory Cache
A Memory Cache is a place where small chunks of key-value data can be stored. Popular examples of memory caches that are used to store session information are Redis and Memcached.
When storing session data in a memory cache, the server will still use a cookie, but the cookie will only contain a unique sessionId
. This sessionId
will be used by the server to perform a lookup against the store.
When using a memory cache, your cookie only contains a session ID. This removes the risk of private user information being exposed in the cookie.
There are some other benefits to using a memory cache to store session information.
- They are normally key-value based and are very quick to perform lookups.
- They normally are decoupled from your application server. This decoupling reduces dependencies.
- A single memory store can serve many applications.
- They automatically manage memory by removing old session data.
However, there are some downsides to them as well:
- They are another server to set up and manage.
- They may be overkill for small applications. Normally database stores (which we will cover next), or cookies will do the job as well.
- There’s no good way to reset the cache without removing all the sessions stored inside it.
Here’s an example of how you can set up a memory cache like Memcached with express-session, via the connect-memcached module.
var express = require('express'); var session = require('express-session'); var cookieParser = require('cookie-parser'); var app = express(); var MemcachedStore = require('connect-memcached')(session); app.use(cookieParser()); app.use(session({ secret : 'some-private-key', key : 'test', proxy : 'true', store : new MemcachedStore({ hosts: ['127.0.0.1:11211'], //this should be where your Memcached server is running secret: 'memcached-secret-key' // Optionally use transparent encryption for memcache session data }) }));
Storing Session Data in a Database
Lastly, let’s talk about storing session data in a traditional database, like MySQL or PostgreSQL. For most cases, this works in a very similar way to storing session data in a memory store.
The session cookie still contains a sessionId
. In this case, it will map to the primary key of the Session table on the database.
Generally speaking, I don’t recommend storing session data in a database, and the only reason why I’d do it is if it was too much effort to set up Memcached or Redis. If you have any strong reasons why a database works better, let me know in the comments.
Retrieving data from a database is slower than a memory cache because the data is stored on disk, not on memory. You’ll be hitting your database a lot when you store your sessions there.
Additionally, you have to completely manage old sessions yourself. If you don’t get rid of old sessions, your database will be filled with thousands of unused rows.
There are numerous database stores that you can use with express-session. View the complete list on the README.
Where should you store your session data?
We’ve talked about the three common places to store your session data. So where should you store your session data?
In general, I follow the rule, “cache first, then cookie, then then database”.
If you have access to Memcached or Redis, I would go with that. If you don’t, store your data in a cookie, but make sure you protect your secret key. Lastly, you can store your data in a database but have a plan to remove old sessions. How do you manage your sessions? Leave a comment and let the community know.
Great article but there seems to be some typos.
“If you’re using a module like express-session, you’ll provide you a nice API to work with sessions (you can get & set data), but under the hood, it will save and retrieve this data using a cookie.”
Oops! Good catch, I fixed it.
I’m using connect-mongo (since it was super easy/quick to set up), and by default it automatically removes expired sessions for you. Expired sessions are those without any activity for 14 days – which is configurable.
This is just one option (of possibly many more) that will allow you to (a) use database-based sessions and (b) not have to completely manage old sessions yourself.
Great article. One question though.
‘Storing Session Data in Cookies’
‘When a user makes a subsequent request to the web server, this cookie gets sent along with the request, and the server can read the information that is in it.”
So when the browser sends back the cookie in a request, how will the browser server link that specific cookie with a specific user if we don’t store the cookie id in a DB when it gets sent the first time?
The cookie is read and decrypted and usually contains the userId, which is then used to fetch further information about the user from the database.
Normally, when you use cookies, you create a “secret” that is used to decrypt the contents of the cookie.
By default, I am pretty sure that Express sessions store data in memory, & use a cookie w/ just a hashed id. So it’s more like the in-memory/memory cache approaches, not like the cookie storage approach, right?
I’m going by https://github.com/expressjs/session/blob/master/README.md