← Back to Tutorials
Beginner
15 min
Beginner friendly
Building a Session Store with Redis
Learn how to implement a Redis-based session store for web applications using Solidis. Perfect for authentication and user state management.
What You'll Learn
- How to store and retrieve session data in Redis
- Implementing session expiration and TTL
- Creating a session manager class
- Integrating with Express.js middleware
Prerequisites
- •Node.js 14+ installed
- •Redis server running locally or remotely
- •Basic understanding of Express.js
- •Familiarity with TypeScript (optional)
1
Project SetupInstall dependencies and initialize the project
Install Dependencies
npm install @vcms-io/solidis express uuid
TypeScript (Optional)
npm install -D @types/express @types/uuid typescript
2
Create Session Manager ClassBuild a reusable session manager using Solidis
1import { SolidisFeaturedClient } from '@vcms-io/solidis/featured';
2import { v4 as uuidv4 } from 'uuid';
3
4export interface SessionData {
5 userId: string;
6 username: string;
7 email: string;
8 createdAt: number;
9 [key: string]: any;
10}
11
12export class SessionStore {
13 private client: SolidisFeaturedClient;
14 private prefix: string;
15 private ttl: number; // in seconds
16
17 constructor(options: {
18 host?: string;
19 port?: number;
20 prefix?: string;
21 ttl?: number;
22 } = {}) {
23 this.client = new SolidisFeaturedClient({
24 host: options.host || '127.0.0.1',
25 port: options.port || 6379,
26 });
27 this.prefix = options.prefix || 'session:';
28 this.ttl = options.ttl || 3600; // 1 hour default
29 }
30
31 async connect(): Promise<void> {
32 await this.client.connect();
33 }
34
35 async disconnect(): Promise<void> {
36 await this.client.quit();
37 }
38
39 private getKey(sessionId: string): string {
40 return `${this.prefix}${sessionId}`;
41 }
42
43 async create(data: SessionData): Promise<string> {
44 const sessionId = uuidv4();
45 const key = this.getKey(sessionId);
46
47 const sessionData = {
48 ...data,
49 createdAt: Date.now(),
50 };
51
52 await this.client.set(
53 key,
54 JSON.stringify(sessionData),
55 { EX: this.ttl }
56 );
57
58 return sessionId;
59 }
60
61 async get(sessionId: string): Promise<SessionData | null> {
62 const key = this.getKey(sessionId);
63 const data = await this.client.get(key);
64
65 if (!data) {
66 return null;
67 }
68
69 return JSON.parse(data.toString());
70 }
71
72 async update(sessionId: string, data: Partial<SessionData>): Promise<boolean> {
73 const key = this.getKey(sessionId);
74 const existingData = await this.get(sessionId);
75
76 if (!existingData) {
77 return false;
78 }
79
80 const updatedData = { ...existingData, ...data };
81 await this.client.set(
82 key,
83 JSON.stringify(updatedData),
84 { EX: this.ttl }
85 );
86
87 return true;
88 }
89
90 async destroy(sessionId: string): Promise<boolean> {
91 const key = this.getKey(sessionId);
92 const result = await this.client.del(key);
93 return result > 0;
94 }
95
96 async refresh(sessionId: string): Promise<boolean> {
97 const key = this.getKey(sessionId);
98 const result = await this.client.expire(key, this.ttl);
99 return result === 1;
100 }
101
102 async exists(sessionId: string): Promise<boolean> {
103 const key = this.getKey(sessionId);
104 const result = await this.client.exists(key);
105 return result === 1;
106 }
107}3
Create Express MiddlewareIntegrate the session store with Express.js
1import express, { Request, Response, NextFunction } from 'express';
2import { SessionStore, SessionData } from './session-store';
3
4// Extend Express Request type
5declare global {
6 namespace Express {
7 interface Request {
8 session?: SessionData;
9 sessionId?: string;
10 }
11 }
12}
13
14export function createSessionMiddleware(store: SessionStore) {
15 return async (req: Request, res: Response, next: NextFunction) => {
16 // Get session ID from cookie
17 const sessionId = req.cookies?.sessionId;
18
19 if (sessionId) {
20 // Try to load existing session
21 const session = await store.get(sessionId);
22
23 if (session) {
24 req.session = session;
25 req.sessionId = sessionId;
26
27 // Refresh session TTL on each request
28 await store.refresh(sessionId);
29 } else {
30 // Session expired, clear cookie
31 res.clearCookie('sessionId');
32 }
33 }
34
35 // Add helper methods to response
36 res.locals.createSession = async (data: SessionData) => {
37 const sessionId = await store.create(data);
38 req.sessionId = sessionId;
39 req.session = data;
40
41 res.cookie('sessionId', sessionId, {
42 httpOnly: true,
43 secure: process.env.NODE_ENV === 'production',
44 maxAge: 3600000, // 1 hour
45 sameSite: 'strict',
46 });
47
48 return sessionId;
49 };
50
51 res.locals.destroySession = async () => {
52 if (req.sessionId) {
53 await store.destroy(req.sessionId);
54 res.clearCookie('sessionId');
55 delete req.session;
56 delete req.sessionId;
57 }
58 };
59
60 next();
61 };
62}4
Usage ExamplePutting it all together in your Express app
1import express from 'express';
2import cookieParser from 'cookie-parser';
3import { SessionStore } from './session-store';
4import { createSessionMiddleware } from './session-middleware';
5
6const app = express();
7const sessionStore = new SessionStore({
8 host: '127.0.0.1',
9 port: 6379,
10 prefix: 'myapp:session:',
11 ttl: 3600, // 1 hour
12});
13
14// Middleware
15app.use(express.json());
16app.use(cookieParser());
17app.use(createSessionMiddleware(sessionStore));
18
19// Login endpoint
20app.post('/api/login', async (req, res) => {
21 const { username, password } = req.body;
22
23 // Validate credentials (simplified)
24 if (username === 'demo' && password === 'password') {
25 const sessionId = await res.locals.createSession({
26 userId: '123',
27 username: 'demo',
28 email: 'demo@example.com',
29 createdAt: Date.now(),
30 });
31
32 return res.json({
33 success: true,
34 sessionId,
35 message: 'Logged in successfully',
36 });
37 }
38
39 res.status(401).json({ error: 'Invalid credentials' });
40});
41
42// Protected endpoint
43app.get('/api/profile', (req, res) => {
44 if (!req.session) {
45 return res.status(401).json({ error: 'Not authenticated' });
46 }
47
48 res.json({
49 user: {
50 userId: req.session.userId,
51 username: req.session.username,
52 email: req.session.email,
53 },
54 });
55});
56
57// Logout endpoint
58app.post('/api/logout', async (req, res) => {
59 await res.locals.destroySession();
60 res.json({ message: 'Logged out successfully' });
61});
62
63// Start server
64async function start() {
65 await sessionStore.connect();
66 app.listen(3000, () => {
67 console.log('Server running on http://localhost:3000');
68 });
69}
70
71start().catch(console.error);Testing Your Session Store
Test Login
curl -X POST http://localhost:3000/api/login \
-H "Content-Type: application/json" \
-d '{"username":"demo","password":"password"}' \
-c cookies.txt
Test Protected Endpoint
curl http://localhost:3000/api/profile -b cookies.txt
Test Logout
curl -X POST http://localhost:3000/api/logout -b cookies.txt
Best Practices & Tips
- ✓Use secure cookies in productionAlways set
httpOnly,secure, andsameSiteflags - ✓Implement session rotationRegenerate session IDs after login to prevent session fixation attacks
- ✓Set appropriate TTL valuesBalance between user experience and security based on your application needs
- ✓Use connection poolingReuse Redis connections across requests for better performance
- ✓Monitor session countsUse
SCANcommand to track active sessions
