208 lines
6.7 KiB
Markdown
Raw Normal View History

# Auth Module
Authentication and authorization for the Customer Portal.
## Architecture Overview
```
auth/
├── application/ # Orchestration layer
│ ├── auth.facade.ts # Main entry point for auth operations
│ ├── auth-login.service.ts
│ └── auth-health.service.ts
├── decorators/
│ └── public.decorator.ts # @Public, @PublicNoSession, @OptionalAuth
├── presentation/http/
│ ├── auth.controller.ts # Login, signup, password endpoints
│ ├── get-started.controller.ts # OTP-based onboarding
│ ├── guards/
│ │ ├── global-auth.guard.ts # JWT validation (APP_GUARD)
│ │ ├── local-auth.guard.ts # Credential validation
│ │ └── failed-login-throttle.guard.ts
│ └── interceptors/
│ └── login-result.interceptor.ts
└── infra/ # Infrastructure services
├── token/ # JWT & token management
├── otp/ # OTP & session management
├── rate-limiting/ # Auth-specific rate limits
└── workflows/ # Multi-step auth flows
```
## Security Features
### Token Management
| Feature | Description |
| ----------------------------- | --------------------------------------- |
| **Access Token** | 15-min expiry, HS256 HMAC-signed |
| **Refresh Token** | 7-day expiry with family-based rotation |
| **Single-Use Password Reset** | Redis-tracked tokens prevent replay |
| **Token Blacklist** | Immediate revocation on logout |
### OTP Security
| Feature | Description |
| ----------------------- | ----------------------------------------------- |
| **Code Generation** | Cryptographically secure 6-digit codes |
| **Expiration** | 10 minutes (configurable) |
| **Max Attempts** | 3 attempts before invalidation |
| **Fingerprint Binding** | Logs warning if verified from different context |
### Rate Limiting
| Endpoint | Limit | Window |
| -------------- | ----------- | ---------- |
| Login | 5 attempts | 15 minutes |
| Signup | 5 attempts | 15 minutes |
| Password Reset | 5 attempts | 15 minutes |
| OTP Send | 5 codes | 5 minutes |
| OTP Verify | 10 attempts | 5 minutes |
## Authentication Flows
### 1. Login Flow
```
POST /auth/login
LocalAuthGuard (validates credentials)
FailedLoginThrottleGuard (rate limiting)
AuthFacade.login()
├─► Generate token pair
├─► Set httpOnly cookies
└─► Return user + session metadata
```
### 2. Password Reset Flow (Single-Use)
```
POST /auth/request-password-reset
PasswordResetTokenService.create()
├─► Generate JWT with tokenId
├─► Store tokenId in Redis (15-min TTL)
└─► Send email with reset link
POST /auth/reset-password
PasswordResetTokenService.consume()
├─► Verify JWT signature & expiry
├─► Check tokenId exists in Redis
├─► Delete tokenId (single-use enforcement)
└─► If already deleted → "Token already used"
```
### 3. Get Started Flow (OTP)
```
POST /auth/get-started/send-code
OtpService.generateAndStore(email, fingerprint)
├─► Generate 6-digit code
├─► Store in Redis with fingerprint
└─► Send email
POST /auth/get-started/verify-code
OtpService.verify(email, code, fingerprint)
├─► Check fingerprint (warn if mismatch)
├─► Validate code
└─► Determine account status
Account Status:
├─► PORTAL_EXISTS → Redirect to login
├─► WHMCS_UNMAPPED → Redirect to migration
├─► SF_UNMAPPED → Complete account
└─► NEW_CUSTOMER → Full signup
```
## Configuration
### Environment Variables
```bash
# JWT Configuration
JWT_SECRET= # Required: HMAC signing key
JWT_SECRET_PREVIOUS= # Optional: Previous keys for rotation (comma-separated)
JWT_ISSUER= # Optional: Token issuer claim
JWT_AUDIENCE= # Optional: Token audience claim
# Token Expiry
ACCESS_TOKEN_EXPIRY=900 # 15 minutes (seconds)
REFRESH_TOKEN_EXPIRY=604800 # 7 days (seconds)
PASSWORD_RESET_TTL_SECONDS=900 # 15 minutes
# OTP Configuration
OTP_TTL_SECONDS=600 # 10 minutes
OTP_MAX_ATTEMPTS=3 # Max verification attempts
# Rate Limiting
LOGIN_RATE_LIMIT_LIMIT=5 # Max attempts
LOGIN_RATE_LIMIT_TTL=900000 # Window in ms (15 min)
LOGIN_CAPTCHA_AFTER_ATTEMPTS=3 # CAPTCHA threshold
# Redis Behavior
AUTH_ALLOW_REDIS_TOKEN_FAILOPEN=false # Continue without Redis
AUTH_REQUIRE_REDIS_FOR_TOKENS=false # Strict Redis requirement
AUTH_MAINTENANCE_MODE=false # Disable auth service
```
## Route Protection
### Decorators
```typescript
// Anyone can access, optionally attach user if token exists
@Public()
// Strict public - no session attachment, no cookies read
@PublicNoSession()
// No token = allow (user=null), invalid token = 401
@OptionalAuth()
// Default: requires valid access token (401 if missing/invalid)
```
### Guard Behavior
| Decorator | Missing Token | Invalid Token | Valid Token |
| ------------------ | ------------- | ------------- | --------------- |
| (none) | 401 | 401 | ✓ user attached |
| @Public() | ✓ | ✓ | ✓ user attached |
| @PublicNoSession() | ✓ | ✓ | ✓ no user |
| @OptionalAuth() | ✓ null user | 401 | ✓ user attached |
## External Integrations
The auth module integrates with:
- **WHMCS**: Account discovery, client creation, credential validation
- **Salesforce**: Account lookup, portal status updates
- **Redis**: Token storage, OTP codes, session management
- **Email (SendGrid)**: OTP codes, password reset links
## Directory Reference
| Directory | Purpose |
| --------------------------- | ---------------------------------------------- |
| `infra/token/` | JWT signing, refresh token rotation, blacklist |
| `infra/otp/` | OTP codes, get-started sessions |
| `infra/rate-limiting/` | Auth-specific rate limiters |
| `infra/workflows/` | Multi-step flows (signup, password, migration) |
| `presentation/http/guards/` | Request validation, token verification |