A comprehensive secure authentication system built with NestJS, implementing advanced JWT token management, secure session handling, and protection against common authentication vulnerabilities.
-
Clone the repository
git clone https://github.com/AnthonyLJ96/Secure-Authentication-API cd Secure-Authentication-API -
Start services with Docker Compose
# Start PostgreSQL, Redis, and Adminer services docker-compose up -d -
Install dependencies
pnpm install
-
Environment Configuration Create a
.envfile in the root directory with the following variables:# Database (using Docker Compose services) DATABASE_URL="postgresql://root:root@localhost:5432/ticketing" # JWT Configuration JWT_ACCESS_SECRET="your-super-secret-access-key-minimum-32-characters" JWT_REFRESH_SECRET="your-super-secret-refresh-key-minimum-32-characters" JWT_ACCESS_EXPIRES_IN="15m" JWT_REFRESH_EXPIRES_IN="7d" # Redis Configuration (using Docker Compose services) REDIS_HOST="localhost" REDIS_PORT=6379 REDIS_DB=0 # Application NODE_ENV="development" PORT=3000
-
Database Setup
# Generate Prisma client npx prisma generate # Run database migrations npx prisma db push # Seed the database with initial data pnpm run db:seed
# Development mode with hot reload
pnpm run start:devThis implementation demonstrates advanced security practices that protect against common authentication vulnerabilities:
- Dual Token Strategy: Separate access tokens (short-lived, 15 minutes) and refresh tokens (long-lived, 7 days)
- Token Rotation: Refresh tokens are automatically rotated on each refresh request
- Unique Token IDs (JTI): Each token has a unique identifier for precise blacklisting
- Secure Token Storage: Refresh tokens stored in httpOnly cookies to prevent XSS attacks
- BCrypt Hashing: Passwords are hashed using bcrypt with salt rounds
- No Plain Text Storage: Original passwords are never stored in the database
- Secure Validation: Password comparison using bcrypt's secure compare function
- Redis-Based Blacklisting: Invalidated tokens are stored in Redis with automatic expiration
- Individual Token Revocation: Single logout invalidates only current session tokens
- Global Session Termination: "Logout from all devices" invalidates ALL user tokens across devices
- Memory Efficient: Blacklist entries automatically expire when tokens would naturally expire
- HttpOnly Flags: Prevents JavaScript access to refresh tokens
- SameSite Strict: Protection against CSRF attacks
- Secure Flag: HTTPS-only transmission in production
- Path Restriction: Cookies only sent to specific endpoints
- Redis Caching: Fast token validation with Redis-based blacklist checking
- Optimized TTL: Blacklist entries expire automatically, preventing memory bloat
- Stateless Design: JWT tokens allow horizontal scaling
Problem: Malicious scripts could steal tokens from localStorage/sessionStorage Solution: Refresh tokens stored in httpOnly cookies, inaccessible to JavaScript
Problem: Malicious sites could make authenticated requests using user's cookies Solution: SameSite=strict cookie policy prevents cross-origin cookie transmission
Problem: Stolen tokens could be used indefinitely by attackers Solution:
- Short-lived access tokens (15 minutes) minimize exposure window
- Token rotation ensures stolen refresh tokens become invalid
- Unique JTI allows precise token revocation
Problem: Attackers could hijack user sessions using fixed session identifiers Solution: New tokens generated on each authentication, no session reuse
Problem: Users could potentially access resources beyond their authorization level Solution:
- Role-based access control integrated into JWT payload
- User existence verification on each request
- Real-time role validation from database
Problem: Weak password storage vulnerable to rainbow table and brute force attacks Solution:
- BCrypt with salt rounds prevents rainbow table attacks
- Secure password comparison prevents timing attacks
- No plain text password storage
Problem: Tokens accidentally exposed in application logs or URL parameters Solution:
- Refresh tokens never exposed in response bodies
- Access tokens only in Authorization headers
- Structured logging excludes sensitive data
Problem: No control over multiple user sessions across different devices Solution:
- "Logout from all devices" functionality
- Timestamp-based token invalidation
- Per-user session tracking
Problem: Token interception during transmission Solution:
- HTTPS enforcement in production
- Secure cookie flags
- Short token lifespans limit exposure
POST /auth/login- User authentication with credentialsPOST /auth/refresh- Refresh access token using refresh tokenPOST /auth/logout- Single device logoutPOST /auth/logout-all-devices- Multi-device session termination
GET /users/profile- Get current user profile- Protected routes require valid JWT access token in Authorization header
- Framework: NestJS with TypeScript
- Database: PostgreSQL with Prisma ORM
- Caching: Redis for token blacklisting
- Authentication: Passport.js with JWT strategy
- Security: BCrypt for password hashing
- JWT Guard: Validates access tokens and checks blacklist
- Local Auth Guard: Handles username/password authentication
- Rate Limiting: (Recommended for production)
- Helmet: (Recommended for security headers)
The application uses the following services managed by Docker Compose:
- PostgreSQL (port 5432): Main database for user data and roles
- Redis (port 6379): Token blacklisting and caching
- Adminer (port 8080): Database administration interface
- Enable HTTPS/TLS encryption
- Implement rate limiting on authentication endpoints
- Add security headers (helmet.js)
- Monitor authentication attempts and failures
- Regular security audits and dependency updates
- Environment-specific JWT secrets (never commit to version control)
- Database connection pooling and Redis clustering for high availability
# Start all services
docker-compose up -d
# Stop all services
docker-compose down
# View service logs
docker-compose logs -f
# Restart specific service
docker-compose restart redis