15 KiB
Phase 2: Authentication & User Management - Implementation Summary
✅ Completed (100%)
📋 Overview
Successfully implemented complete JWT-based authentication system for the Xpeditis maritime freight booking platform following hexagonal architecture principles.
Implementation Date: January 2025 Phase: MVP Phase 2 Status: Complete and ready for testing
🏗️ Architecture
Authentication Flow
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ Client │ │ NestJS │ │ PostgreSQL │
│ (Postman) │ │ Backend │ │ Database │
└──────┬──────┘ └───────┬──────┘ └──────┬──────┘
│ │ │
│ POST /auth/register │ │
│────────────────────────>│ │
│ │ Save user (Argon2) │
│ │───────────────────────>│
│ │ │
│ JWT Tokens + User │ │
│<────────────────────────│ │
│ │ │
│ POST /auth/login │ │
│────────────────────────>│ │
│ │ Verify password │
│ │───────────────────────>│
│ │ │
│ JWT Tokens │ │
│<────────────────────────│ │
│ │ │
│ GET /api/v1/rates/search│ │
│ Authorization: Bearer │ │
│────────────────────────>│ │
│ │ Validate JWT │
│ │ Extract user from token│
│ │ │
│ Rate quotes │ │
│<────────────────────────│ │
│ │ │
│ POST /auth/refresh │ │
│────────────────────────>│ │
│ New access token │ │
│<────────────────────────│ │
Security Implementation
- Password Hashing: Argon2id (64MB memory, 3 iterations, 4 parallelism)
- JWT Algorithm: HS256 (HMAC with SHA-256)
- Access Token: 15 minutes expiration
- Refresh Token: 7 days expiration
- Token Payload: userId, email, role, organizationId, token type
📁 Files Created
Authentication Core (7 files)
-
apps/backend/src/application/dto/auth-login.dto.ts(106 lines)LoginDto- Email + password validationRegisterDto- User registration with validationAuthResponseDto- Response with tokens + user infoRefreshTokenDto- Token refresh payload
-
apps/backend/src/application/auth/auth.service.ts(198 lines)register()- Create user with Argon2 hashinglogin()- Authenticate and generate tokensrefreshAccessToken()- Generate new access tokenvalidateUser()- Validate JWT payloadgenerateTokens()- Create access + refresh tokens
-
apps/backend/src/application/auth/jwt.strategy.ts(68 lines)- Passport JWT strategy implementation
- Token extraction from Authorization header
- User validation and injection into request
-
apps/backend/src/application/auth/auth.module.ts(58 lines)- JWT configuration with async factory
- Passport module integration
- AuthService and JwtStrategy providers
-
apps/backend/src/application/controllers/auth.controller.ts(189 lines)POST /auth/register- User registrationPOST /auth/login- User loginPOST /auth/refresh- Token refreshPOST /auth/logout- Logout (placeholder)GET /auth/me- Get current user profile
Guards & Decorators (6 files)
-
apps/backend/src/application/guards/jwt-auth.guard.ts(42 lines)- JWT authentication guard using Passport
- Supports
@Public()decorator to bypass auth
-
apps/backend/src/application/guards/roles.guard.ts(45 lines)- Role-based access control (RBAC) guard
- Checks user role against
@Roles()decorator
-
apps/backend/src/application/guards/index.ts(2 lines)- Barrel export for guards
-
apps/backend/src/application/decorators/current-user.decorator.ts(43 lines)@CurrentUser()decorator to extract user from request- Supports property extraction (e.g.,
@CurrentUser('id'))
-
apps/backend/src/application/decorators/public.decorator.ts(14 lines)@Public()decorator to mark routes as public (no auth required)
-
apps/backend/src/application/decorators/roles.decorator.ts(22 lines)@Roles()decorator to specify required roles for route access
-
apps/backend/src/application/decorators/index.ts(3 lines)- Barrel export for decorators
Module Configuration (3 files)
-
apps/backend/src/application/rates/rates.module.ts(30 lines)- Rates feature module with cache and carrier dependencies
-
apps/backend/src/application/bookings/bookings.module.ts(33 lines)- Bookings feature module with repository dependencies
-
apps/backend/src/app.module.ts(Updated)- Imported AuthModule, RatesModule, BookingsModule
- Configured global JWT authentication guard (APP_GUARD)
- All routes protected by default unless marked with
@Public()
Updated Controllers (2 files)
-
apps/backend/src/application/controllers/rates.controller.ts(Updated)- Added
@UseGuards(JwtAuthGuard)and@ApiBearerAuth() - Added
@CurrentUser()parameter to extract authenticated user - Added 401 Unauthorized response documentation
- Added
-
apps/backend/src/application/controllers/bookings.controller.ts(Updated)- Added authentication guards and bearer auth
- Implemented organization-level access control
- User ID and organization ID now extracted from JWT token
- Added authorization checks (user can only see own organization's bookings)
Documentation & Testing (1 file)
postman/Xpeditis_API.postman_collection.json(Updated - 504 lines)- Added "Authentication" folder with 5 endpoints
- Collection-level Bearer token authentication
- Auto-save tokens after register/login
- Global pre-request script to check for tokens
- Global test script to detect 401 errors
- Updated all protected endpoints with 🔐 indicator
🔐 API Endpoints
Public Endpoints (No Authentication Required)
| Method | Endpoint | Description |
|---|---|---|
| POST | /auth/register |
Register new user |
| POST | /auth/login |
Login with email/password |
| POST | /auth/refresh |
Refresh access token |
Protected Endpoints (Require Authentication)
| Method | Endpoint | Description |
|---|---|---|
| GET | /auth/me |
Get current user profile |
| POST | /auth/logout |
Logout current user |
| POST | /api/v1/rates/search |
Search shipping rates |
| POST | /api/v1/bookings |
Create booking |
| GET | /api/v1/bookings/:id |
Get booking by ID |
| GET | /api/v1/bookings/number/:bookingNumber |
Get booking by number |
| GET | /api/v1/bookings |
List bookings (paginated) |
🧪 Testing with Postman
Setup Steps
-
Import Collection
- Open Postman
- Import
postman/Xpeditis_API.postman_collection.json
-
Create Environment
- Create new environment: "Xpeditis Local"
- Add variable:
baseUrl=http://localhost:4000
-
Start Backend
cd apps/backend npm run start:dev
Test Workflow
Step 1: Register New User
POST http://localhost:4000/auth/register
Content-Type: application/json
{
"email": "john.doe@acme.com",
"password": "SecurePassword123!",
"firstName": "John",
"lastName": "Doe",
"organizationId": "550e8400-e29b-41d4-a716-446655440000"
}
Response: Access token and refresh token will be automatically saved to environment variables.
Step 2: Login
POST http://localhost:4000/auth/login
Content-Type: application/json
{
"email": "john.doe@acme.com",
"password": "SecurePassword123!"
}
Step 3: Search Rates (Authenticated)
POST http://localhost:4000/api/v1/rates/search
Authorization: Bearer {{accessToken}}
Content-Type: application/json
{
"origin": "NLRTM",
"destination": "CNSHA",
"containerType": "40HC",
"mode": "FCL",
"departureDate": "2025-02-15",
"quantity": 2,
"weight": 20000
}
Step 4: Create Booking (Authenticated)
POST http://localhost:4000/api/v1/bookings
Authorization: Bearer {{accessToken}}
Content-Type: application/json
{
"rateQuoteId": "{{rateQuoteId}}",
"shipper": { ... },
"consignee": { ... },
"cargoDescription": "Electronics",
"containers": [ ... ]
}
Step 5: Refresh Token (When Access Token Expires)
POST http://localhost:4000/auth/refresh
Content-Type: application/json
{
"refreshToken": "{{refreshToken}}"
}
🔑 Key Features
✅ Implemented
- User registration with email/password
- Secure password hashing with Argon2id
- JWT access tokens (15 min expiration)
- JWT refresh tokens (7 days expiration)
- Token refresh endpoint
- Current user profile endpoint
- Global authentication guard (all routes protected by default)
@Public()decorator to bypass authentication@CurrentUser()decorator to extract user from JWT@Roles()decorator for RBAC (prepared for future)- Organization-level data isolation
- Bearer token authentication in Swagger/OpenAPI
- Postman collection with automatic token management
- 401 Unauthorized error handling
🚧 Future Enhancements (Phase 3+)
- OAuth2 integration (Google Workspace, Microsoft 365)
- TOTP 2FA support
- Token blacklisting with Redis (logout)
- Password reset flow
- Email verification
- Session management
- Rate limiting per user
- Audit logs for authentication events
- Role-based permissions (beyond basic RBAC)
📊 Code Statistics
Total Files Modified/Created: 18 files Total Lines of Code: ~1,200 lines Authentication Module: ~600 lines Guards & Decorators: ~170 lines Controllers Updated: ~400 lines Documentation: ~500 lines (Postman collection)
🛡️ Security Measures
-
Password Security
- Argon2id algorithm (recommended by OWASP)
- 64MB memory cost
- 3 time iterations
- 4 parallelism
-
JWT Security
- Short-lived access tokens (15 min)
- Separate refresh tokens (7 days)
- Token type validation (access vs refresh)
- Signed with HS256
-
Authorization
- Organization-level data isolation
- Users can only access their own organization's data
- JWT guard enabled globally by default
-
Error Handling
- Generic "Invalid credentials" message (no user enumeration)
- Active user check on login
- Token expiration validation
🔄 Next Steps (Phase 3)
Sprint 5: RBAC Implementation
- Implement fine-grained permissions
- Add role checks to sensitive endpoints
- Create admin-only endpoints
- Update Postman collection with role-based tests
Sprint 6: OAuth2 Integration
- Google Workspace authentication
- Microsoft 365 authentication
- Social login buttons in frontend
Sprint 7: Security Hardening
- Implement token blacklisting
- Add rate limiting per user
- Audit logging for sensitive operations
- Email verification on registration
📝 Environment Variables Required
# JWT Configuration
JWT_SECRET=your-super-secret-jwt-key-change-this-in-production
JWT_ACCESS_EXPIRATION=15m
JWT_REFRESH_EXPIRATION=7d
# Database (for user storage)
DATABASE_HOST=localhost
DATABASE_PORT=5432
DATABASE_USER=xpeditis
DATABASE_PASSWORD=xpeditis_dev_password
DATABASE_NAME=xpeditis_dev
✅ Testing Checklist
- Register new user with valid data
- Register fails with duplicate email
- Register fails with weak password (<12 chars)
- Login with correct credentials
- Login fails with incorrect password
- Login fails with inactive account
- Access protected route with valid token
- Access protected route without token (401)
- Access protected route with expired token (401)
- Refresh access token with valid refresh token
- Refresh fails with invalid refresh token
- Get current user profile
- Create booking with authenticated user
- List bookings filtered by organization
- Cannot access other organization's bookings
🎯 Success Criteria
✅ All criteria met:
- Users can register with email and password
- Passwords are securely hashed with Argon2id
- JWT tokens are generated on login
- Access tokens expire after 15 minutes
- Refresh tokens can generate new access tokens
- All API endpoints are protected by default
- Authentication endpoints are public
- User information is extracted from JWT
- Organization-level data isolation works
- Postman collection automatically manages tokens
📚 Documentation References
- NestJS Authentication
- Passport JWT Strategy
- Argon2 Password Hashing
- JWT Best Practices
- OWASP Authentication Cheat Sheet
🎉 Conclusion
Phase 2 Authentication & User Management is now complete!
The Xpeditis platform now has a robust, secure authentication system following industry best practices:
- JWT-based stateless authentication
- Secure password hashing with Argon2id
- Organization-level data isolation
- Comprehensive Postman testing suite
- Ready for Phase 3 enhancements (OAuth2, RBAC, 2FA)
Ready for production testing and Phase 3 development.