servcraft 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +29 -0
- package/.github/CODEOWNERS +18 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +46 -0
- package/.github/dependabot.yml +59 -0
- package/.github/workflows/ci.yml +188 -0
- package/.github/workflows/release.yml +195 -0
- package/AUDIT.md +602 -0
- package/README.md +1070 -1
- package/dist/cli/index.cjs +2026 -2168
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +2026 -2168
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +595 -616
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +114 -52
- package/dist/index.d.ts +114 -52
- package/dist/index.js +595 -616
- package/dist/index.js.map +1 -1
- package/docs/CLI-001_MULTI_DB_PLAN.md +546 -0
- package/docs/DATABASE_MULTI_ORM.md +399 -0
- package/docs/PHASE1_BREAKDOWN.md +346 -0
- package/docs/PROGRESS.md +550 -0
- package/docs/modules/ANALYTICS.md +226 -0
- package/docs/modules/API-VERSIONING.md +252 -0
- package/docs/modules/AUDIT.md +192 -0
- package/docs/modules/AUTH.md +431 -0
- package/docs/modules/CACHE.md +346 -0
- package/docs/modules/EMAIL.md +254 -0
- package/docs/modules/FEATURE-FLAG.md +291 -0
- package/docs/modules/I18N.md +294 -0
- package/docs/modules/MEDIA-PROCESSING.md +281 -0
- package/docs/modules/MFA.md +266 -0
- package/docs/modules/NOTIFICATION.md +311 -0
- package/docs/modules/OAUTH.md +237 -0
- package/docs/modules/PAYMENT.md +804 -0
- package/docs/modules/QUEUE.md +540 -0
- package/docs/modules/RATE-LIMIT.md +339 -0
- package/docs/modules/SEARCH.md +288 -0
- package/docs/modules/SECURITY.md +327 -0
- package/docs/modules/SESSION.md +382 -0
- package/docs/modules/SWAGGER.md +305 -0
- package/docs/modules/UPLOAD.md +296 -0
- package/docs/modules/USER.md +505 -0
- package/docs/modules/VALIDATION.md +294 -0
- package/docs/modules/WEBHOOK.md +270 -0
- package/docs/modules/WEBSOCKET.md +691 -0
- package/package.json +53 -38
- package/prisma/schema.prisma +395 -1
- package/src/cli/commands/add-module.ts +520 -87
- package/src/cli/commands/db.ts +3 -4
- package/src/cli/commands/docs.ts +256 -6
- package/src/cli/commands/generate.ts +12 -19
- package/src/cli/commands/init.ts +384 -214
- package/src/cli/index.ts +0 -4
- package/src/cli/templates/repository.ts +6 -1
- package/src/cli/templates/routes.ts +6 -21
- package/src/cli/utils/docs-generator.ts +6 -7
- package/src/cli/utils/env-manager.ts +717 -0
- package/src/cli/utils/field-parser.ts +16 -7
- package/src/cli/utils/interactive-prompt.ts +223 -0
- package/src/cli/utils/template-manager.ts +346 -0
- package/src/config/database.config.ts +183 -0
- package/src/config/env.ts +0 -10
- package/src/config/index.ts +0 -14
- package/src/core/server.ts +1 -1
- package/src/database/adapters/mongoose.adapter.ts +132 -0
- package/src/database/adapters/prisma.adapter.ts +118 -0
- package/src/database/connection.ts +190 -0
- package/src/database/interfaces/database.interface.ts +85 -0
- package/src/database/interfaces/index.ts +7 -0
- package/src/database/interfaces/repository.interface.ts +129 -0
- package/src/database/models/mongoose/index.ts +7 -0
- package/src/database/models/mongoose/payment.schema.ts +347 -0
- package/src/database/models/mongoose/user.schema.ts +154 -0
- package/src/database/prisma.ts +1 -4
- package/src/database/redis.ts +101 -0
- package/src/database/repositories/mongoose/index.ts +7 -0
- package/src/database/repositories/mongoose/payment.repository.ts +380 -0
- package/src/database/repositories/mongoose/user.repository.ts +255 -0
- package/src/database/seed.ts +6 -1
- package/src/index.ts +9 -20
- package/src/middleware/security.ts +2 -6
- package/src/modules/analytics/analytics.routes.ts +80 -0
- package/src/modules/analytics/analytics.service.ts +364 -0
- package/src/modules/analytics/index.ts +18 -0
- package/src/modules/analytics/types.ts +180 -0
- package/src/modules/api-versioning/index.ts +15 -0
- package/src/modules/api-versioning/types.ts +86 -0
- package/src/modules/api-versioning/versioning.middleware.ts +120 -0
- package/src/modules/api-versioning/versioning.routes.ts +54 -0
- package/src/modules/api-versioning/versioning.service.ts +189 -0
- package/src/modules/audit/audit.repository.ts +206 -0
- package/src/modules/audit/audit.service.ts +27 -59
- package/src/modules/auth/auth.controller.ts +2 -2
- package/src/modules/auth/auth.middleware.ts +3 -9
- package/src/modules/auth/auth.routes.ts +10 -107
- package/src/modules/auth/auth.service.ts +126 -23
- package/src/modules/auth/index.ts +3 -4
- package/src/modules/cache/cache.service.ts +367 -0
- package/src/modules/cache/index.ts +10 -0
- package/src/modules/cache/types.ts +44 -0
- package/src/modules/email/email.service.ts +3 -10
- package/src/modules/email/templates.ts +2 -8
- package/src/modules/feature-flag/feature-flag.repository.ts +303 -0
- package/src/modules/feature-flag/feature-flag.routes.ts +247 -0
- package/src/modules/feature-flag/feature-flag.service.ts +566 -0
- package/src/modules/feature-flag/index.ts +20 -0
- package/src/modules/feature-flag/types.ts +192 -0
- package/src/modules/i18n/i18n.middleware.ts +186 -0
- package/src/modules/i18n/i18n.routes.ts +191 -0
- package/src/modules/i18n/i18n.service.ts +456 -0
- package/src/modules/i18n/index.ts +18 -0
- package/src/modules/i18n/types.ts +118 -0
- package/src/modules/media-processing/index.ts +17 -0
- package/src/modules/media-processing/media-processing.routes.ts +111 -0
- package/src/modules/media-processing/media-processing.service.ts +245 -0
- package/src/modules/media-processing/types.ts +156 -0
- package/src/modules/mfa/index.ts +20 -0
- package/src/modules/mfa/mfa.repository.ts +206 -0
- package/src/modules/mfa/mfa.routes.ts +595 -0
- package/src/modules/mfa/mfa.service.ts +572 -0
- package/src/modules/mfa/totp.ts +150 -0
- package/src/modules/mfa/types.ts +57 -0
- package/src/modules/notification/index.ts +20 -0
- package/src/modules/notification/notification.repository.ts +356 -0
- package/src/modules/notification/notification.service.ts +483 -0
- package/src/modules/notification/types.ts +119 -0
- package/src/modules/oauth/index.ts +20 -0
- package/src/modules/oauth/oauth.repository.ts +219 -0
- package/src/modules/oauth/oauth.routes.ts +446 -0
- package/src/modules/oauth/oauth.service.ts +293 -0
- package/src/modules/oauth/providers/apple.provider.ts +250 -0
- package/src/modules/oauth/providers/facebook.provider.ts +181 -0
- package/src/modules/oauth/providers/github.provider.ts +248 -0
- package/src/modules/oauth/providers/google.provider.ts +189 -0
- package/src/modules/oauth/providers/twitter.provider.ts +214 -0
- package/src/modules/oauth/types.ts +94 -0
- package/src/modules/payment/index.ts +19 -0
- package/src/modules/payment/payment.repository.ts +733 -0
- package/src/modules/payment/payment.routes.ts +390 -0
- package/src/modules/payment/payment.service.ts +354 -0
- package/src/modules/payment/providers/mobile-money.provider.ts +274 -0
- package/src/modules/payment/providers/paypal.provider.ts +190 -0
- package/src/modules/payment/providers/stripe.provider.ts +215 -0
- package/src/modules/payment/types.ts +140 -0
- package/src/modules/queue/cron.ts +438 -0
- package/src/modules/queue/index.ts +87 -0
- package/src/modules/queue/queue.routes.ts +600 -0
- package/src/modules/queue/queue.service.ts +842 -0
- package/src/modules/queue/types.ts +222 -0
- package/src/modules/queue/workers.ts +366 -0
- package/src/modules/rate-limit/index.ts +59 -0
- package/src/modules/rate-limit/rate-limit.middleware.ts +134 -0
- package/src/modules/rate-limit/rate-limit.routes.ts +269 -0
- package/src/modules/rate-limit/rate-limit.service.ts +348 -0
- package/src/modules/rate-limit/stores/memory.store.ts +165 -0
- package/src/modules/rate-limit/stores/redis.store.ts +322 -0
- package/src/modules/rate-limit/types.ts +153 -0
- package/src/modules/search/adapters/elasticsearch.adapter.ts +326 -0
- package/src/modules/search/adapters/meilisearch.adapter.ts +261 -0
- package/src/modules/search/adapters/memory.adapter.ts +278 -0
- package/src/modules/search/index.ts +21 -0
- package/src/modules/search/search.service.ts +234 -0
- package/src/modules/search/types.ts +214 -0
- package/src/modules/security/index.ts +40 -0
- package/src/modules/security/sanitize.ts +223 -0
- package/src/modules/security/security-audit.service.ts +388 -0
- package/src/modules/security/security.middleware.ts +398 -0
- package/src/modules/session/index.ts +3 -0
- package/src/modules/session/session.repository.ts +159 -0
- package/src/modules/session/session.service.ts +340 -0
- package/src/modules/session/types.ts +38 -0
- package/src/modules/swagger/index.ts +7 -1
- package/src/modules/swagger/schema-builder.ts +16 -4
- package/src/modules/swagger/swagger.service.ts +9 -10
- package/src/modules/swagger/types.ts +0 -2
- package/src/modules/upload/index.ts +14 -0
- package/src/modules/upload/types.ts +83 -0
- package/src/modules/upload/upload.repository.ts +199 -0
- package/src/modules/upload/upload.routes.ts +311 -0
- package/src/modules/upload/upload.service.ts +448 -0
- package/src/modules/user/index.ts +3 -3
- package/src/modules/user/user.controller.ts +15 -9
- package/src/modules/user/user.repository.ts +237 -113
- package/src/modules/user/user.routes.ts +39 -164
- package/src/modules/user/user.service.ts +4 -3
- package/src/modules/validation/validator.ts +12 -17
- package/src/modules/webhook/index.ts +91 -0
- package/src/modules/webhook/retry.ts +196 -0
- package/src/modules/webhook/signature.ts +135 -0
- package/src/modules/webhook/types.ts +181 -0
- package/src/modules/webhook/webhook.repository.ts +358 -0
- package/src/modules/webhook/webhook.routes.ts +442 -0
- package/src/modules/webhook/webhook.service.ts +457 -0
- package/src/modules/websocket/features.ts +504 -0
- package/src/modules/websocket/index.ts +106 -0
- package/src/modules/websocket/middlewares.ts +298 -0
- package/src/modules/websocket/types.ts +181 -0
- package/src/modules/websocket/websocket.service.ts +692 -0
- package/src/utils/errors.ts +7 -0
- package/src/utils/pagination.ts +4 -1
- package/tests/helpers/db-check.ts +79 -0
- package/tests/integration/auth-redis.test.ts +94 -0
- package/tests/integration/cache-redis.test.ts +387 -0
- package/tests/integration/mongoose-repositories.test.ts +410 -0
- package/tests/integration/payment-prisma.test.ts +637 -0
- package/tests/integration/queue-bullmq.test.ts +417 -0
- package/tests/integration/user-prisma.test.ts +441 -0
- package/tests/integration/websocket-socketio.test.ts +552 -0
- package/tests/setup.ts +11 -9
- package/vitest.config.ts +3 -8
- package/npm-cache/_cacache/content-v2/sha512/1c/d0/03440d500a0487621aad1d6402978340698976602046db8e24fa03c01ee6c022c69b0582f969042d9442ee876ac35c038e960dd427d1e622fa24b8eb7dba +0 -0
- package/npm-cache/_cacache/content-v2/sha512/42/55/28b493ca491833e5aab0e9c3108d29ab3f36c248ca88f45d4630674fce9130959e56ae308797ac2b6328fa7f09a610b9550ed09cb971d039876d293fc69d +0 -0
- package/npm-cache/_cacache/content-v2/sha512/e0/12/f360dc9315ee5f17844a0c8c233ee6bf7c30837c4a02ea0d56c61c7f7ab21c0e958e50ed2c57c59f983c762b93056778c9009b2398ffc26def0183999b13 +0 -0
- package/npm-cache/_cacache/content-v2/sha512/ed/b0/fae1161902898f4c913c67d7f6cdf6be0665aec3b389b9c4f4f0a101ca1da59badf1b59c4e0030f5223023b8d63cfe501c46a32c20c895d4fb3f11ca2232 +0 -0
- package/npm-cache/_cacache/index-v5/58/94/c2cba79e0f16b4c10e95a87e32255741149e8222cc314a476aab67c39cc0 +0 -5
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
# Auth Module Documentation
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The Auth module provides JWT-based authentication with support for access/refresh tokens, token blacklisting, and user session management.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- ✅ JWT access and refresh tokens
|
|
10
|
+
- ✅ Token blacklisting with Redis (token revocation)
|
|
11
|
+
- ✅ Password hashing with bcrypt (12 rounds)
|
|
12
|
+
- ✅ Role-based access control (RBAC)
|
|
13
|
+
- ✅ Token rotation on refresh
|
|
14
|
+
- ✅ Graceful fallback to in-memory (development only)
|
|
15
|
+
|
|
16
|
+
## Architecture
|
|
17
|
+
|
|
18
|
+
### Components
|
|
19
|
+
|
|
20
|
+
1. **AuthService** (`auth.service.ts`)
|
|
21
|
+
- Token generation and verification
|
|
22
|
+
- Password hashing and verification
|
|
23
|
+
- **Redis-based token blacklist** ✅ (Updated 2025-12-19)
|
|
24
|
+
- OAuth support methods
|
|
25
|
+
|
|
26
|
+
2. **AuthController** (`auth.controller.ts`)
|
|
27
|
+
- HTTP endpoints for authentication
|
|
28
|
+
- Request validation
|
|
29
|
+
- Response formatting
|
|
30
|
+
|
|
31
|
+
3. **AuthMiddleware** (`auth.middleware.ts`)
|
|
32
|
+
- JWT verification middleware
|
|
33
|
+
- Role-based authorization
|
|
34
|
+
|
|
35
|
+
## Token Blacklist Implementation
|
|
36
|
+
|
|
37
|
+
### Redis Connection
|
|
38
|
+
|
|
39
|
+
The AuthService now uses Redis for token blacklisting:
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
const authService = new AuthService(fastifyInstance, 'redis://localhost:6379');
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**Environment variable:**
|
|
46
|
+
```bash
|
|
47
|
+
REDIS_URL=redis://localhost:6379
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### How it works
|
|
51
|
+
|
|
52
|
+
1. **On Logout**: Token is added to Redis with 7-day TTL
|
|
53
|
+
```typescript
|
|
54
|
+
await authService.blacklistToken(token);
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
2. **On Token Verification**: Checks Redis for blacklisted tokens
|
|
58
|
+
```typescript
|
|
59
|
+
const isBlacklisted = await authService.isTokenBlacklisted(token);
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
3. **Automatic Expiry**: Redis TTL automatically removes expired tokens (7 days)
|
|
63
|
+
|
|
64
|
+
### Fallback Behavior
|
|
65
|
+
|
|
66
|
+
If Redis is not available:
|
|
67
|
+
- **Blacklisting**: Issues a warning, doesn't store token
|
|
68
|
+
- **Verification**: Returns `false` (allows access)
|
|
69
|
+
- **Recommendation**: Use Redis in production for security
|
|
70
|
+
|
|
71
|
+
## API Endpoints
|
|
72
|
+
|
|
73
|
+
### POST `/auth/register`
|
|
74
|
+
|
|
75
|
+
Register a new user.
|
|
76
|
+
|
|
77
|
+
**Request:**
|
|
78
|
+
```json
|
|
79
|
+
{
|
|
80
|
+
"email": "user@example.com",
|
|
81
|
+
"password": "SecurePassword123!",
|
|
82
|
+
"name": "John Doe"
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**Response:**
|
|
87
|
+
```json
|
|
88
|
+
{
|
|
89
|
+
"success": true,
|
|
90
|
+
"data": {
|
|
91
|
+
"user": {
|
|
92
|
+
"id": "uuid",
|
|
93
|
+
"email": "user@example.com",
|
|
94
|
+
"name": "John Doe",
|
|
95
|
+
"role": "user"
|
|
96
|
+
},
|
|
97
|
+
"accessToken": "eyJhbGc...",
|
|
98
|
+
"refreshToken": "eyJhbGc...",
|
|
99
|
+
"expiresIn": 900
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### POST `/auth/login`
|
|
105
|
+
|
|
106
|
+
Authenticate a user.
|
|
107
|
+
|
|
108
|
+
**Request:**
|
|
109
|
+
```json
|
|
110
|
+
{
|
|
111
|
+
"email": "user@example.com",
|
|
112
|
+
"password": "SecurePassword123!"
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
**Response:**
|
|
117
|
+
```json
|
|
118
|
+
{
|
|
119
|
+
"success": true,
|
|
120
|
+
"data": {
|
|
121
|
+
"user": {
|
|
122
|
+
"id": "uuid",
|
|
123
|
+
"email": "user@example.com",
|
|
124
|
+
"name": "John Doe",
|
|
125
|
+
"role": "user"
|
|
126
|
+
},
|
|
127
|
+
"accessToken": "eyJhbGc...",
|
|
128
|
+
"refreshToken": "eyJhbGc...",
|
|
129
|
+
"expiresIn": 900
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### POST `/auth/refresh`
|
|
135
|
+
|
|
136
|
+
Refresh access token using refresh token.
|
|
137
|
+
|
|
138
|
+
**Request:**
|
|
139
|
+
```json
|
|
140
|
+
{
|
|
141
|
+
"refreshToken": "eyJhbGc..."
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
**Response:**
|
|
146
|
+
```json
|
|
147
|
+
{
|
|
148
|
+
"success": true,
|
|
149
|
+
"data": {
|
|
150
|
+
"accessToken": "eyJhbGc...",
|
|
151
|
+
"refreshToken": "eyJhbGc...",
|
|
152
|
+
"expiresIn": 900
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
**Note:** The old refresh token is automatically blacklisted (token rotation).
|
|
158
|
+
|
|
159
|
+
### POST `/auth/logout`
|
|
160
|
+
|
|
161
|
+
Logout and blacklist current token.
|
|
162
|
+
|
|
163
|
+
**Headers:**
|
|
164
|
+
```
|
|
165
|
+
Authorization: Bearer eyJhbGc...
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
**Response:**
|
|
169
|
+
```json
|
|
170
|
+
{
|
|
171
|
+
"success": true,
|
|
172
|
+
"data": {
|
|
173
|
+
"message": "Logged out successfully"
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### GET `/auth/me`
|
|
179
|
+
|
|
180
|
+
Get current user profile.
|
|
181
|
+
|
|
182
|
+
**Headers:**
|
|
183
|
+
```
|
|
184
|
+
Authorization: Bearer eyJhbGc...
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
**Response:**
|
|
188
|
+
```json
|
|
189
|
+
{
|
|
190
|
+
"success": true,
|
|
191
|
+
"data": {
|
|
192
|
+
"id": "uuid",
|
|
193
|
+
"email": "user@example.com",
|
|
194
|
+
"name": "John Doe",
|
|
195
|
+
"role": "user",
|
|
196
|
+
"status": "active",
|
|
197
|
+
"createdAt": "2025-12-19T..."
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### POST `/auth/change-password`
|
|
203
|
+
|
|
204
|
+
Change user password.
|
|
205
|
+
|
|
206
|
+
**Headers:**
|
|
207
|
+
```
|
|
208
|
+
Authorization: Bearer eyJhbGc...
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
**Request:**
|
|
212
|
+
```json
|
|
213
|
+
{
|
|
214
|
+
"currentPassword": "OldPassword123!",
|
|
215
|
+
"newPassword": "NewPassword123!"
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
**Response:**
|
|
220
|
+
```json
|
|
221
|
+
{
|
|
222
|
+
"success": true,
|
|
223
|
+
"data": {
|
|
224
|
+
"message": "Password changed successfully"
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
## Configuration
|
|
230
|
+
|
|
231
|
+
### Environment Variables
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
# JWT Configuration
|
|
235
|
+
JWT_SECRET=your-super-secret-key-min-32-characters
|
|
236
|
+
JWT_ACCESS_EXPIRES_IN=15m
|
|
237
|
+
JWT_REFRESH_EXPIRES_IN=7d
|
|
238
|
+
|
|
239
|
+
# Redis for Token Blacklist
|
|
240
|
+
REDIS_URL=redis://localhost:6379
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### Token Expiration
|
|
244
|
+
|
|
245
|
+
- **Access Token**: 15 minutes (default)
|
|
246
|
+
- **Refresh Token**: 7 days (default)
|
|
247
|
+
- **Blacklist TTL**: 7 days (matches refresh token)
|
|
248
|
+
|
|
249
|
+
## Security Features
|
|
250
|
+
|
|
251
|
+
### Password Security
|
|
252
|
+
- ✅ Bcrypt hashing with 12 rounds
|
|
253
|
+
- ✅ Minimum 8 characters (validated)
|
|
254
|
+
- ✅ Password complexity (recommended, not enforced)
|
|
255
|
+
|
|
256
|
+
### Token Security
|
|
257
|
+
- ✅ Separate access and refresh tokens
|
|
258
|
+
- ✅ Token type verification
|
|
259
|
+
- ✅ Token blacklisting on logout
|
|
260
|
+
- ✅ Token rotation on refresh
|
|
261
|
+
- ✅ Short-lived access tokens
|
|
262
|
+
|
|
263
|
+
### Session Security
|
|
264
|
+
- ✅ Last login tracking
|
|
265
|
+
- ✅ Account status check (active/inactive/suspended)
|
|
266
|
+
- ✅ Multi-instance support (via Redis)
|
|
267
|
+
|
|
268
|
+
## Usage Examples
|
|
269
|
+
|
|
270
|
+
### Basic Authentication Flow
|
|
271
|
+
|
|
272
|
+
```typescript
|
|
273
|
+
// 1. Register
|
|
274
|
+
const registerResponse = await fetch('/auth/register', {
|
|
275
|
+
method: 'POST',
|
|
276
|
+
headers: { 'Content-Type': 'application/json' },
|
|
277
|
+
body: JSON.stringify({
|
|
278
|
+
email: 'user@example.com',
|
|
279
|
+
password: 'Password123!',
|
|
280
|
+
name: 'John Doe'
|
|
281
|
+
})
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
const { data } = await registerResponse.json();
|
|
285
|
+
const { accessToken, refreshToken } = data;
|
|
286
|
+
|
|
287
|
+
// 2. Use access token
|
|
288
|
+
const meResponse = await fetch('/auth/me', {
|
|
289
|
+
headers: { 'Authorization': `Bearer ${accessToken}` }
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
// 3. Refresh token when expired
|
|
293
|
+
const refreshResponse = await fetch('/auth/refresh', {
|
|
294
|
+
method: 'POST',
|
|
295
|
+
headers: { 'Content-Type': 'application/json' },
|
|
296
|
+
body: JSON.stringify({ refreshToken })
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
// 4. Logout
|
|
300
|
+
await fetch('/auth/logout', {
|
|
301
|
+
method: 'POST',
|
|
302
|
+
headers: { 'Authorization': `Bearer ${accessToken}` }
|
|
303
|
+
});
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
### Using Auth Middleware
|
|
307
|
+
|
|
308
|
+
```typescript
|
|
309
|
+
import { authMiddleware, roleGuard } from './modules/auth';
|
|
310
|
+
|
|
311
|
+
// Protect route with authentication
|
|
312
|
+
fastify.get('/protected', {
|
|
313
|
+
preHandler: authMiddleware
|
|
314
|
+
}, async (request, reply) => {
|
|
315
|
+
// Access user: request.user
|
|
316
|
+
reply.send({ user: request.user });
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
// Protect route with role
|
|
320
|
+
fastify.get('/admin', {
|
|
321
|
+
preHandler: [authMiddleware, roleGuard(['admin', 'super_admin'])]
|
|
322
|
+
}, async (request, reply) => {
|
|
323
|
+
reply.send({ message: 'Admin area' });
|
|
324
|
+
});
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
## Production Checklist
|
|
328
|
+
|
|
329
|
+
- [ ] Set strong `JWT_SECRET` (min 32 characters)
|
|
330
|
+
- [ ] Configure `REDIS_URL` for token blacklist
|
|
331
|
+
- [ ] Use HTTPS in production
|
|
332
|
+
- [ ] Enable rate limiting on auth endpoints
|
|
333
|
+
- [ ] Monitor failed login attempts
|
|
334
|
+
- [ ] Implement MFA for sensitive accounts
|
|
335
|
+
- [ ] Regular security audits
|
|
336
|
+
- [ ] Log authentication events (audit trail)
|
|
337
|
+
|
|
338
|
+
## Troubleshooting
|
|
339
|
+
|
|
340
|
+
### Token blacklist not working
|
|
341
|
+
|
|
342
|
+
**Problem**: Revoked tokens still work after logout.
|
|
343
|
+
|
|
344
|
+
**Solution**: Verify Redis connection:
|
|
345
|
+
```bash
|
|
346
|
+
redis-cli ping
|
|
347
|
+
# Should return: PONG
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
Check logs for Redis connection errors:
|
|
351
|
+
```bash
|
|
352
|
+
grep "Redis connection error" logs/app.log
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
### Redis connection failed
|
|
356
|
+
|
|
357
|
+
**Problem**: Auth service can't connect to Redis.
|
|
358
|
+
|
|
359
|
+
**Solution**:
|
|
360
|
+
1. Check if Redis is running: `redis-cli ping`
|
|
361
|
+
2. Verify `REDIS_URL` environment variable
|
|
362
|
+
3. Check network connectivity
|
|
363
|
+
4. Check Redis authentication (if required)
|
|
364
|
+
|
|
365
|
+
### High Redis memory usage
|
|
366
|
+
|
|
367
|
+
**Problem**: Too many blacklisted tokens in Redis.
|
|
368
|
+
|
|
369
|
+
**Solution**: Check blacklist count:
|
|
370
|
+
```typescript
|
|
371
|
+
const count = await authService.getBlacklistCount();
|
|
372
|
+
console.log(`Blacklisted tokens: ${count}`);
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
Redis automatically expires tokens after 7 days (TTL). If memory is still high:
|
|
376
|
+
1. Reduce `JWT_REFRESH_EXPIRES_IN`
|
|
377
|
+
2. Reduce `BLACKLIST_TTL` in `auth.service.ts`
|
|
378
|
+
3. Monitor and clean up manually if needed
|
|
379
|
+
|
|
380
|
+
## Migration Notes
|
|
381
|
+
|
|
382
|
+
### v0.1.0 → v0.2.0 (2025-12-19)
|
|
383
|
+
|
|
384
|
+
**Breaking Change**: Token blacklist now requires Redis.
|
|
385
|
+
|
|
386
|
+
**Migration steps:**
|
|
387
|
+
|
|
388
|
+
1. Install and start Redis:
|
|
389
|
+
```bash
|
|
390
|
+
docker run -d -p 6379:6379 redis:7-alpine
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
2. Set environment variable:
|
|
394
|
+
```bash
|
|
395
|
+
echo "REDIS_URL=redis://localhost:6379" >> .env
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
3. Update AuthService instantiation to pass Redis URL:
|
|
399
|
+
```typescript
|
|
400
|
+
// Before
|
|
401
|
+
const authService = new AuthService(fastifyInstance);
|
|
402
|
+
|
|
403
|
+
// After (optional, reads from env)
|
|
404
|
+
const authService = new AuthService(fastifyInstance, process.env.REDIS_URL);
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
4. Test logout and verify token revocation:
|
|
408
|
+
```bash
|
|
409
|
+
# Login
|
|
410
|
+
TOKEN=$(curl -X POST /auth/login -d '{"email":"...","password":"..."}' | jq -r '.data.accessToken')
|
|
411
|
+
|
|
412
|
+
# Logout
|
|
413
|
+
curl -X POST /auth/logout -H "Authorization: Bearer $TOKEN"
|
|
414
|
+
|
|
415
|
+
# Try to use token (should fail)
|
|
416
|
+
curl /auth/me -H "Authorization: Bearer $TOKEN"
|
|
417
|
+
# Expected: 401 Unauthorized
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
## Related Modules
|
|
421
|
+
|
|
422
|
+
- **User Module**: User management and profiles
|
|
423
|
+
- **MFA Module**: Two-factor authentication
|
|
424
|
+
- **OAuth Module**: Social login providers
|
|
425
|
+
- **Audit Module**: Authentication event logging
|
|
426
|
+
|
|
427
|
+
## References
|
|
428
|
+
|
|
429
|
+
- [JWT Best Practices](https://tools.ietf.org/html/rfc8725)
|
|
430
|
+
- [OWASP Authentication Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html)
|
|
431
|
+
- [Redis Documentation](https://redis.io/docs/)
|