The Auth Module provides a complete JWT-based authentication system for the LogiQuest API. It handles user registration, login, password hashing with bcrypt, and provides JWT token validation through guards.
- ✅ User registration with username, email, and password
- ✅ Secure login with JWT token generation
- ✅ Password hashing using bcrypt (10 rounds)
- ✅ JWT token validation via
JwtAuthGuard - ✅ Configurable token expiry via environment variables
- ✅ Proper error handling with descriptive messages
- ✅ UUID-based user IDs for scalability
Create a .env file in the project root with the following variables:
DATABASE_URL=postgresql://user:password@localhost:5432/logiquest
JWT_SECRET=your-super-secret-jwt-key-change-this-in-production
JWT_EXPIRY=7d
PORT=3000JWT_EXPIRY can be set to:
1h- 1 hour7d- 7 days (default)24h- 24 hours- Any valid ms format duration
POST /auth/register
Request body:
{
"username": "john_doe",
"email": "john@example.com",
"password": "securepassword123"
}Success response (201):
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"username": "john_doe",
"email": "john@example.com",
"createdAt": "2024-01-15T10:30:00Z",
"updatedAt": "2024-01-15T10:30:00Z"
}Error responses:
400 Bad Request- Invalid input format409 Conflict- Username or email already exists
POST /auth/login
Request body:
{
"username": "john_doe",
"password": "securepassword123"
}Success response (200):
{
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"username": "john_doe",
"email": "john@example.com"
}
}Error responses:
401 Unauthorized- Invalid username or password
Protect routes by applying the JwtAuthGuard to controller methods:
import { UseGuards, Get } from '@nestjs/common';
import { JwtAuthGuard } from './auth/guards/jwt-auth.guard';
@Controller('users')
export class UsersController {
@Get('profile')
@UseGuards(JwtAuthGuard)
getProfile(@Req() req) {
return req.user; // Returns the authenticated user
}
}import { UseGuards, Controller } from '@nestjs/common';
import { JwtAuthGuard } from './auth/guards/jwt-auth.guard';
@Controller('dashboard')
@UseGuards(JwtAuthGuard)
export class DashboardController {
// All routes in this controller are protected
}Include the JWT token in the Authorization header:
curl -X GET http://localhost:3000/users/profile \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."const token = response.data.accessToken;
const config = {
headers: {
Authorization: `Bearer ${token}`
}
};
axios.get('/users/profile', config);const token = response.accessToken;
const headers = {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
};
fetch('/users/profile', { headers });src/auth/
├── auth.module.ts # Main module definition
├── auth.controller.ts # API endpoints (register, login)
├── auth.service.ts # Business logic
├── dto/
│ ├── register.dto.ts # Registration request DTO
│ └── login.dto.ts # Login request DTO
├── entities/
│ └── user.entity.ts # User database entity
├── guards/
│ └── jwt-auth.guard.ts # JWT authentication guard
└── strategies/
└── jwt.strategy.ts # Passport JWT strategy
The users table is automatically created with:
| Column | Type | Constraints |
|---|---|---|
| id | UUID | PRIMARY KEY |
| username | VARCHAR | UNIQUE, NOT NULL |
| VARCHAR | UNIQUE, NOT NULL | |
| password | VARCHAR | NOT NULL (hashed) |
| createdAt | TIMESTAMP | Auto-set on creation |
| updatedAt | TIMESTAMP | Auto-update on change |
The JWT token contains the following claims:
{
"sub": "550e8400-e29b-41d4-a716-446655440000", // User ID
"username": "john_doe",
"email": "john@example.com",
"iat": 1705314600, // Issued at
"exp": 1706000000 // Expiration
}The auth module returns standardized error responses:
{
"statusCode": 401,
"message": "Invalid credentials",
"error": "Unauthorized"
}{
"statusCode": 401,
"message": "Unauthorized access - valid JWT token required",
"error": "Unauthorized"
}{
"statusCode": 409,
"message": "Username or email already exists",
"error": "Conflict"
}- Password Hashing: Passwords are hashed with bcrypt using 10 rounds
- Token Storage: Store tokens securely in HTTP-only cookies or secure storage
- HTTPS: Always use HTTPS in production
- Secret Management: Use strong, randomly generated JWT_SECRET
- Token Expiry: Set appropriate expiry times (7 days recommended)
- CORS: Configure CORS appropriately for your frontend
Once the auth module is set up, other modules can protect their endpoints:
// Example: In any controller
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
@Controller('scoring')
export class ScoringController {
@Post('submit')
@UseGuards(JwtAuthGuard)
submitScore(@Req() req) {
const userId = req.user.id;
// ... rest of implementation
}
}curl -X POST http://localhost:3000/auth/register \
-H "Content-Type: application/json" \
-d '{
"username": "testuser",
"email": "test@example.com",
"password": "testpass123"
}'curl -X POST http://localhost:3000/auth/login \
-H "Content-Type: application/json" \
-d '{
"username": "testuser",
"password": "testpass123"
}'curl -X GET http://localhost:3000/users/profile \
-H "Authorization: Bearer <your-access-token>"# Development mode with hot reload
npm run start:dev
# Production build
npm run build
# Production mode
npm run start:prod- Ensure
JWT_SECRETmatches between token generation and validation - Check token hasn't expired (verify
JWT_EXPIRYconfiguration) - Verify Authorization header format:
Bearer <token>
- Verify
DATABASE_URLis correct - Ensure PostgreSQL is running
- Check user permissions and database existence
- Ensure bcrypt is installed:
npm list bcrypt - Rebuild native modules if needed:
npm rebuild bcrypt
- Add email verification for registration
- Implement password reset functionality
- Add refresh token mechanism
- Implement role-based access control (RBAC)
- Add rate limiting on auth endpoints
- Implement two-factor authentication (2FA)