Securing your Express + TypeScript apps: Using Sessions and Redis
Express.js is a powerful web application framework for Node.js, and when building web applications, session management is a crucial aspect. express-session
is a middleware that provides session support in Express applications. If you want to enhance the performance and scalability of your session management, using redis
as a session store is a great choice.
This blog post will guide you through the process of setting up and using express-session
with redis
in a Node.js applications written in TypeScript.
Why we need sessions?
Maintaining State Across Requests: HTTP is a stateless protocol, meaning it treats each request from a client to server as independent. Sessions allow developers to maintain state across multiple requests. For example, a shopping cart app needs to remember the items a user has added to their cart as they navigate through different pages.
User Identification and Authentication: Sessions are often used to keep track of user identity across multiple requests. When a user logs into an application, a session can be established to persist their identity throughout their interaction with the application.
Security: Sessions can securely store sensitive user information on the server side. This helps mitigate security risks associated with storing information on the client side, where it might be vulnerable to attacks.
Caching and Performance Optimization: Sessions can be utilized to cache frequently accessed data, reducing the need to fetch or compute it on every request. This can contribute to improved performance and a more responsive user experience.
Prerequisites
Before we begin, make sure you have the following installed:
- Node.js and npm — You can download them from https://nodejs.org/.
- TypeScript — Install it globally using
npm install -g typescript
. - An Express.js project initialized with TypeScript. If you haven’t set up an Express.js project with TypeScript, you can create one using the following command:
npx tsc --init
. This will generate atsconfig.json
file. Make sure to configure it according to your project structure. - Redis server — Ensure that you have a running Redis server. You can download it from https://redis.io/download.
Implementation
Install the necessary packages express-session, ioredis, connect-redis
and their types @types/ioredis @types/express-session
using npm install
-
npm install express-session ioredis connect-redis
npm install @types/ioredis @types/express-session
In your entry file, import these libraries —
import session from "express-session";
import IORedis from "ioredis";
import RedisStore from "connect-redis";
Redis
is an in-memory data structure store that can be used as a caching layer or a persistent key-value database. We will be using the ioredis
node library to create a connection using a redis url or you can connect to your local redis instance —
const redisClient = new IORedis(process.env.REDIS_URL || "redis://127.0.0.1:6379");
connect-redis
provides a session store for Express applications. Instead of storing session data in the server's memory, it utilizes a Redis database to store session information. Using the redis client connection, create a redis store using the connect-redis
library.
const redisStore = new RedisStore({ client: redisClient });
Finally, add the redis store to the session which will be used by the app as the middleware. Provide a secret key which will be used for signing the session ID cookie. This should remain private for security concerns.
We are using httpOnlyCookies to ensure that session cookies cannot be accessed via JavaScript. This is crucial to preventing cookie theft via XSS attacks. Set a maxAge to the cookies so that the session can be expired after some time.
app.use(
session({
store: redisStore,
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
cookie: {
secure: false,
httpOnly: true,
maxAge: 1000 * 60 * 60 * 3,
}
})
)
Using the session object is as easier than just setting a key-value pair in an object. Just add the values like this —
login = async (req: Request, res: Response) => {
// logic for login method goes here...
// store the userId and user's email in the session
req.session.userId = userId;
req.session.email = email;
}
Access the stored data in the session easily using console.log(req.session.userId)
and to destroy the session — req.session.destroy
Common issue faced by the users
While setting up express-session
and redis
in typescript node apps, you might run into errors like —
This might happen if you have imported connect-redis
in your app using import connectRedis from “connect-redis”
and then initializing the RedisStore using const RedisStore = connectRedis(session).
import session from "express-session";
import connectRedis from "connect-redis";
const RedisStore = connectRedis(session);
For this to work, instead of initializing the RedisStore
in express-session,
import it directly from connect-redis
. Also, if you were using @types/connect-redis
, you can remove that now since types are now included in the main package. These are few of the breaking changes made in the v7 of the connect-redis
library. For more information, check out their release announcement here.
Working code snippet —
import session from "express-session";
import IORedis from 'ioredis';
import RedisStore from "connect-redis";
const redisClient = new IORedis(process.env.REDIS_URL || "redis://127.0.0.1:6379");
app.use(
session({
store: new RedisStore({ client: redisClient }),
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
cookie: {
secure: false,
httpOnly: true,
maxAge: 1000 * 60 * 60 * 3,
},
})
)
Congratulations! You’ve successfully set up express-session
with ioredis
in a Node.js application using TypeScript. This combination allows for efficient and scalable session management in your Express.js web application.
I hope you found this post useful and please do let me know in case of any question or query. Leave a comment here and I will surely reply!
Happy coding!