A NestJS application demonstrating four robust authentication strategies:
- JWT Authentication (Stateless tokens)
- Server-Side Sessions (Session store with Redis)
- Hybrid Authentication (Combines both approaches)
- Access + Refresh Tokens (Token rotation strategy)
git clone https://github.com/4ssh1/session-management.gitpnpm install- Copy
.env.exampleto.envand adjust configuration as needed
pnpm docker:up- Generate and run migrations as required
pnpm start:dev- NestJS – Backend framework
- PostgreSQL – User data storage
- Redis – Session storage
- Passport.js – Authentication middleware
- Bcrypt – Password hashing
- TypeORM – Database ORM
- Docker, Jest, Supertest – DevOps & Testing
src
┣ auth
┃ ┣ decorators
┃ ┃ ┗ current.user.decorator.ts
┃ ┣ dto
┃ ┃ ┣ login.dto.ts
┃ ┃ ┗ register.dto.ts
┃ ┣ guards
┃ ┃ ┣ hybrid.guard.ts
┃ ┃ ┣ jwt.guard.spec.ts
┃ ┃ ┣ jwt.guard.ts
┃ ┃ ┣ refresh-token.guard.ts
┃ ┃ ┣ session.guard.spec.ts
┃ ┃ ┗ session.guard.ts
┃ ┣ interfaces
┃ ┃ ┗ jwt.interface.ts
┃ ┣ strategies
┃ ┃ ┣ hybrid.strategy.ts
┃ ┃ ┣ jwt.strategy.ts
┃ ┃ ┣ refresh-token.strategy.ts
┃ ┃ ┗ session.strategy.ts
┃ ┣ auth.controller.ts
┃ ┣ auth.module.ts
┃ ┣ auth.service.spec.ts
┃ ┗ auth.service.ts
┣ db
┃ ┗ db.module.ts
┣ redis
┃ ┗ redis.module.ts
┣ session
┃ ┣ dto
┃ ┃ ┣ create-session.dto.ts
┃ ┃ ┗ update-session.dto.ts
┃ ┣ session.controller.ts
┃ ┣ session.module.ts
┃ ┣ session.service.spec.ts
┃ ┗ session.service.ts
┣ users
┃ ┣ dto
┃ ┃ ┣ create-user.dto.ts
┃ ┃ ┗ update-user.dto.ts
┃ ┣ entities
┃ ┃ ┗ user.entity.ts
┃ ┣ users.controller.spec.ts
┃ ┣ users.controller.ts
┃ ┣ users.module.ts
┃ ┣ users.service.spec.ts
┃ ┗ users.service.ts
┣ app.controller.spec.ts
┣ app.controller.ts
┣ app.module.ts
┣ app.service.ts
┗ main.ts
strategies/– Passport authentication strategiesguards/– Route protection logicdecorators/– Custom decorators (e.g., current user extraction)dto/– Data transfer objects for validation
Stateless authentication: the token itself carries all necessary user information. The server verifies the token's signature without maintaining a session.
Flow:
- User logs in with credentials
- Server generates a JWT with user payload
- Client stores token (e.g., localStorage)
- Client sends token in the
Authorizationheader on each request - Server verifies the token’s signature
Pros
- Scalable (no server session state)
- Works across domains
Cons
- Cannot easily invalidate tokens
- Token size can be large
- Compromised tokens can allow unauthorized access
A session ID is stored in a secure HTTP-only cookie, while session data is kept on the server (Redis). Each request validates the session via Redis.
Flow:
- User logs in
- Server creates a session in Redis
- Session ID sent to client (HTTP-only cookie)
- Client sends cookie automatically
- Server validates session with Redis on each request
Pros
- Immediate session invalidation
- Server-controlled security (e.g., secure cookies)
Cons
- Can require sticky sessions for scalability
- Needs session storage
Leverages JWT for stateless authentication but stores token IDs in Redis whitelist for revocation.
Flow:
- User logs in, receives JWT
- Token ID stored in Redis whitelist
- Each request: server checks JWT validity and Redis whitelist
- Logout removes token from whitelist
Pros
- Scalable as JWT
- Immediate revocation
Cons
- Redis lookup on each request
- More complex setup
A "Best Practice" strategy: short-lived access tokens for requests, long-lived refresh tokens for renewal.
Flow:
- Login issues access (e.g., 15m) & refresh tokens (e.g., 7d)
- API requests use access token
- Expired access token can be renewed with refresh token
- Server issues new access (& optionally refresh) tokens on renewal
Token Rotation:
- On refresh, the server issues a new refresh token and invalidates the old
- Attempts to reuse an old refresh token can be detected (token theft)
Pros
- Minimal damage if access token compromised
- Refresh tokens can be revoked for security
Cons
- More complex implementation
- Secure storage for refresh tokens required
- User registration & validation
- Duplicate email prevention
- Login with valid/invalid credentials
- Access for protected routes
- Invalid token rejection
- Cookie-based auth
- Session persistence
- Logout and session destruction
- Denial without valid session
- Token whitelisting
- Immediate token revocation
- Denial with revoked/JWT
- Whitelist checks on every request
- Access & refresh token issuance
- Rotation on refresh
- Invalidating stale refresh tokens
- Token theft checks
- Validation of token type
- Isolation: Each test is independent
- Cleanup: Cleans up test data
- Mocking: External dependencies are mocked for unit tests
- Real Integration: E2E tests use real DB/Redis
- Coverage: All critical flows tested
- Assertions: Clear, direct expectations
- Naming: Descriptive, self-explanatory test names
View all test output:
pnpm test -- --verboseRun a specific test:
pnpm test -- --testNamePattern="should register new user"Debugging with Node Inspector:
node --inspect-brk node_modules/.bin/jest --runInBandContributions welcome! Please open an issue or submit a pull request to help improve this project.