securepool 1.0.0

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.
Files changed (126) hide show
  1. package/.dockerignore +7 -0
  2. package/.env.example +20 -0
  3. package/ARCHITECTURE.md +279 -0
  4. package/DEPLOYMENT.md +441 -0
  5. package/README.md +283 -0
  6. package/SETUP.md +388 -0
  7. package/apps/demo-backend/Dockerfile +33 -0
  8. package/apps/demo-backend/package.json +19 -0
  9. package/apps/demo-backend/src/index.ts +71 -0
  10. package/apps/demo-backend/tsconfig.json +8 -0
  11. package/apps/demo-frontend/.env.example +2 -0
  12. package/apps/demo-frontend/README.md +73 -0
  13. package/apps/demo-frontend/eslint.config.js +23 -0
  14. package/apps/demo-frontend/index.html +13 -0
  15. package/apps/demo-frontend/package.json +24 -0
  16. package/apps/demo-frontend/public/favicon.svg +1 -0
  17. package/apps/demo-frontend/public/icons.svg +24 -0
  18. package/apps/demo-frontend/src/App.tsx +33 -0
  19. package/apps/demo-frontend/src/assets/hero.png +0 -0
  20. package/apps/demo-frontend/src/assets/vite.svg +1 -0
  21. package/apps/demo-frontend/src/components/AccountSwitcher.tsx +373 -0
  22. package/apps/demo-frontend/src/components/ChangePasswordModal.tsx +128 -0
  23. package/apps/demo-frontend/src/index.css +272 -0
  24. package/apps/demo-frontend/src/main.tsx +10 -0
  25. package/apps/demo-frontend/src/pages/DashboardPage.tsx +141 -0
  26. package/apps/demo-frontend/src/pages/ForgotPasswordPage.tsx +183 -0
  27. package/apps/demo-frontend/src/pages/LoginPage.tsx +158 -0
  28. package/apps/demo-frontend/src/pages/OtpLoginPage.tsx +114 -0
  29. package/apps/demo-frontend/src/pages/SignupPage.tsx +95 -0
  30. package/apps/demo-frontend/src/pages/VerifyEmailPage.tsx +84 -0
  31. package/apps/demo-frontend/tsconfig.app.json +28 -0
  32. package/apps/demo-frontend/tsconfig.json +7 -0
  33. package/apps/demo-frontend/tsconfig.node.json +26 -0
  34. package/apps/demo-frontend/vite.config.ts +15 -0
  35. package/docs/DATABASE_MONGODB.md +280 -0
  36. package/docs/DATABASE_SQL.md +472 -0
  37. package/package.json +21 -0
  38. package/packages/api/package.json +30 -0
  39. package/packages/api/src/createSecurePool.ts +113 -0
  40. package/packages/api/src/index.ts +8 -0
  41. package/packages/api/src/middleware/authMiddleware.ts +26 -0
  42. package/packages/api/src/middleware/authorize.ts +24 -0
  43. package/packages/api/src/middleware/rateLimiter.ts +25 -0
  44. package/packages/api/src/middleware/tenantMiddleware.ts +12 -0
  45. package/packages/api/src/routes/authRoutes.ts +229 -0
  46. package/packages/api/src/routes/sessionRoutes.ts +30 -0
  47. package/packages/api/src/swagger.ts +529 -0
  48. package/packages/api/tsconfig.json +8 -0
  49. package/packages/application/package.json +16 -0
  50. package/packages/application/src/index.ts +17 -0
  51. package/packages/application/src/interfaces/IAuditLogRepository.ts +6 -0
  52. package/packages/application/src/interfaces/IAuthPlugin.ts +4 -0
  53. package/packages/application/src/interfaces/IEmailService.ts +3 -0
  54. package/packages/application/src/interfaces/IGoogleAuthService.ts +3 -0
  55. package/packages/application/src/interfaces/IOtpRepository.ts +8 -0
  56. package/packages/application/src/interfaces/IOtpService.ts +4 -0
  57. package/packages/application/src/interfaces/IPasswordHasher.ts +4 -0
  58. package/packages/application/src/interfaces/IRoleRepository.ts +8 -0
  59. package/packages/application/src/interfaces/ISessionRepository.ts +8 -0
  60. package/packages/application/src/interfaces/ITokenRepository.ts +9 -0
  61. package/packages/application/src/interfaces/ITokenService.ts +5 -0
  62. package/packages/application/src/interfaces/IUserRepository.ts +8 -0
  63. package/packages/application/src/services/AuthService.ts +323 -0
  64. package/packages/application/src/services/RefreshTokenService.ts +53 -0
  65. package/packages/application/tsconfig.json +8 -0
  66. package/packages/core/package.json +13 -0
  67. package/packages/core/src/entities/AuditLog.ts +11 -0
  68. package/packages/core/src/entities/OtpCode.ts +10 -0
  69. package/packages/core/src/entities/RefreshToken.ts +9 -0
  70. package/packages/core/src/entities/Role.ts +6 -0
  71. package/packages/core/src/entities/Session.ts +10 -0
  72. package/packages/core/src/entities/Tenant.ts +7 -0
  73. package/packages/core/src/entities/User.ts +10 -0
  74. package/packages/core/src/entities/UserRole.ts +6 -0
  75. package/packages/core/src/enums/index.ts +22 -0
  76. package/packages/core/src/index.ts +10 -0
  77. package/packages/core/tsconfig.json +8 -0
  78. package/packages/infrastructure/package.json +24 -0
  79. package/packages/infrastructure/src/email/NodemailerEmailService.ts +55 -0
  80. package/packages/infrastructure/src/google/GoogleAuthServiceImpl.ts +28 -0
  81. package/packages/infrastructure/src/hashing/BcryptHasher.ts +18 -0
  82. package/packages/infrastructure/src/index.ts +6 -0
  83. package/packages/infrastructure/src/jwt/JwtTokenService.ts +32 -0
  84. package/packages/infrastructure/src/otp/OtpServiceImpl.ts +50 -0
  85. package/packages/infrastructure/tsconfig.json +8 -0
  86. package/packages/persistence/package.json +22 -0
  87. package/packages/persistence/prisma/schema.prisma +88 -0
  88. package/packages/persistence/src/factory.ts +48 -0
  89. package/packages/persistence/src/index.ts +30 -0
  90. package/packages/persistence/src/mongo/connection.ts +9 -0
  91. package/packages/persistence/src/mongo/models/AuditLogModel.ts +21 -0
  92. package/packages/persistence/src/mongo/models/OtpModel.ts +19 -0
  93. package/packages/persistence/src/mongo/models/RefreshTokenModel.ts +17 -0
  94. package/packages/persistence/src/mongo/models/RoleModel.ts +11 -0
  95. package/packages/persistence/src/mongo/models/SessionModel.ts +19 -0
  96. package/packages/persistence/src/mongo/models/UserModel.ts +21 -0
  97. package/packages/persistence/src/mongo/models/UserRoleModel.ts +15 -0
  98. package/packages/persistence/src/mongo/repositories/MongoAuditLogRepository.ts +29 -0
  99. package/packages/persistence/src/mongo/repositories/MongoOtpRepository.ts +34 -0
  100. package/packages/persistence/src/mongo/repositories/MongoRoleRepository.ts +32 -0
  101. package/packages/persistence/src/mongo/repositories/MongoSessionRepository.ts +29 -0
  102. package/packages/persistence/src/mongo/repositories/MongoTokenRepository.ts +34 -0
  103. package/packages/persistence/src/mongo/repositories/MongoUserRepository.ts +37 -0
  104. package/packages/persistence/src/prisma/repositories/PrismaAuditLogRepository.ts +37 -0
  105. package/packages/persistence/src/prisma/repositories/PrismaOtpRepository.ts +43 -0
  106. package/packages/persistence/src/prisma/repositories/PrismaRoleRepository.ts +36 -0
  107. package/packages/persistence/src/prisma/repositories/PrismaSessionRepository.ts +39 -0
  108. package/packages/persistence/src/prisma/repositories/PrismaTokenRepository.ts +50 -0
  109. package/packages/persistence/src/prisma/repositories/PrismaUserRepository.ts +45 -0
  110. package/packages/persistence/tsconfig.json +8 -0
  111. package/packages/react-sdk/package.json +23 -0
  112. package/packages/react-sdk/src/components/GoogleLoginButton.tsx +54 -0
  113. package/packages/react-sdk/src/components/LoginForm.tsx +67 -0
  114. package/packages/react-sdk/src/components/OTPVerification.tsx +104 -0
  115. package/packages/react-sdk/src/components/SessionList.tsx +64 -0
  116. package/packages/react-sdk/src/components/SignupForm.tsx +95 -0
  117. package/packages/react-sdk/src/context/AuthContext.ts +4 -0
  118. package/packages/react-sdk/src/context/SecurePoolProvider.tsx +492 -0
  119. package/packages/react-sdk/src/hooks/useAuth.ts +11 -0
  120. package/packages/react-sdk/src/index.ts +22 -0
  121. package/packages/react-sdk/src/types.ts +53 -0
  122. package/packages/react-sdk/tsconfig.json +12 -0
  123. package/scripts/setup.js +285 -0
  124. package/scripts/setup.sh +309 -0
  125. package/tsconfig.base.json +16 -0
  126. package/turbo.json +16 -0
@@ -0,0 +1,529 @@
1
+ import { Express } from "express";
2
+ import swaggerUi from "swagger-ui-express";
3
+
4
+ const swaggerDocument = {
5
+ openapi: "3.0.3",
6
+ info: {
7
+ title: "SecurePool API",
8
+ description:
9
+ "Production-grade authentication framework. Supports JWT, OTP, Google SSO, multi-tenancy, session management, and RBAC.",
10
+ version: "1.0.0",
11
+ contact: {
12
+ name: "SecurePool",
13
+ },
14
+ },
15
+ servers: [
16
+ {
17
+ url: "http://localhost:5001",
18
+ description: "Local Development",
19
+ },
20
+ ],
21
+ tags: [
22
+ { name: "Auth", description: "Registration, login, OTP, password management" },
23
+ { name: "Sessions", description: "Device session management" },
24
+ { name: "Health", description: "Server health check" },
25
+ ],
26
+ components: {
27
+ securitySchemes: {
28
+ BearerAuth: {
29
+ type: "http",
30
+ scheme: "bearer",
31
+ bearerFormat: "JWT",
32
+ description: "Paste your access token here (from login/register response)",
33
+ },
34
+ },
35
+ parameters: {
36
+ TenantId: {
37
+ in: "header",
38
+ name: "x-tenant-id",
39
+ required: true,
40
+ schema: { type: "string", default: "default" },
41
+ description: "Tenant identifier",
42
+ },
43
+ },
44
+ schemas: {
45
+ Error: {
46
+ type: "object",
47
+ properties: {
48
+ error: { type: "string", example: "Invalid email or password" },
49
+ },
50
+ },
51
+ TokenResponse: {
52
+ type: "object",
53
+ properties: {
54
+ accessToken: { type: "string", example: "eyJhbGciOiJSUzI1NiIs..." },
55
+ refreshToken: { type: "string", example: "bd5ce14f4253c157c81d..." },
56
+ },
57
+ },
58
+ Session: {
59
+ type: "object",
60
+ properties: {
61
+ id: { type: "string", example: "69bfe6bdd7fe5fc5acf93dec" },
62
+ userId: { type: "string", example: "69bfe6b6d7fe5fc5acf93de5" },
63
+ device: { type: "string", example: "Chrome on Mac OS" },
64
+ ip: { type: "string", example: "::1" },
65
+ createdAt: { type: "string", format: "date-time" },
66
+ isActive: { type: "boolean", example: true },
67
+ },
68
+ },
69
+ },
70
+ },
71
+ paths: {
72
+ "/health": {
73
+ get: {
74
+ tags: ["Health"],
75
+ summary: "Health check",
76
+ responses: {
77
+ 200: {
78
+ description: "Server is running",
79
+ content: {
80
+ "application/json": {
81
+ schema: {
82
+ type: "object",
83
+ properties: { status: { type: "string", example: "ok" } },
84
+ },
85
+ },
86
+ },
87
+ },
88
+ },
89
+ },
90
+ },
91
+
92
+ // ===== AUTH =====
93
+
94
+ "/auth/register": {
95
+ post: {
96
+ tags: ["Auth"],
97
+ summary: "Register new user",
98
+ description:
99
+ "Validates email uniqueness, hashes password, and sends a 6-digit OTP to the email. **Does NOT create the user yet** — call `/auth/verify-email` with the OTP to complete registration.",
100
+ parameters: [{ $ref: "#/components/parameters/TenantId" }],
101
+ requestBody: {
102
+ required: true,
103
+ content: {
104
+ "application/json": {
105
+ schema: {
106
+ type: "object",
107
+ required: ["email", "password"],
108
+ properties: {
109
+ email: { type: "string", format: "email", example: "user@example.com" },
110
+ password: { type: "string", minLength: 8, example: "MyPass@1234" },
111
+ },
112
+ },
113
+ },
114
+ },
115
+ },
116
+ responses: {
117
+ 200: {
118
+ description: "OTP sent to email",
119
+ content: {
120
+ "application/json": {
121
+ schema: {
122
+ type: "object",
123
+ properties: {
124
+ message: { type: "string", example: "OTP sent to your email. Verify to complete registration." },
125
+ email: { type: "string", example: "user@example.com" },
126
+ },
127
+ },
128
+ },
129
+ },
130
+ },
131
+ 400: { description: "Validation error", content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } } },
132
+ },
133
+ },
134
+ },
135
+
136
+ "/auth/verify-email": {
137
+ post: {
138
+ tags: ["Auth"],
139
+ summary: "Verify email OTP (complete registration)",
140
+ description:
141
+ "Verifies the 6-digit OTP sent during registration. On success, creates the user account and returns JWT tokens.",
142
+ parameters: [{ $ref: "#/components/parameters/TenantId" }],
143
+ requestBody: {
144
+ required: true,
145
+ content: {
146
+ "application/json": {
147
+ schema: {
148
+ type: "object",
149
+ required: ["email", "code"],
150
+ properties: {
151
+ email: { type: "string", format: "email", example: "user@example.com" },
152
+ code: { type: "string", minLength: 6, maxLength: 6, example: "482910" },
153
+ },
154
+ },
155
+ },
156
+ },
157
+ },
158
+ responses: {
159
+ 200: { description: "User created + tokens", content: { "application/json": { schema: { $ref: "#/components/schemas/TokenResponse" } } } },
160
+ 400: { description: "Invalid OTP or expired", content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } } },
161
+ },
162
+ },
163
+ },
164
+
165
+ "/auth/login": {
166
+ post: {
167
+ tags: ["Auth"],
168
+ summary: "Login with email & password",
169
+ description: "Authenticates user and returns JWT access token + refresh token. Also creates a device session.",
170
+ parameters: [{ $ref: "#/components/parameters/TenantId" }],
171
+ requestBody: {
172
+ required: true,
173
+ content: {
174
+ "application/json": {
175
+ schema: {
176
+ type: "object",
177
+ required: ["email", "password"],
178
+ properties: {
179
+ email: { type: "string", format: "email", example: "user@example.com" },
180
+ password: { type: "string", example: "MyPass@1234" },
181
+ },
182
+ },
183
+ },
184
+ },
185
+ },
186
+ responses: {
187
+ 200: { description: "Login successful", content: { "application/json": { schema: { $ref: "#/components/schemas/TokenResponse" } } } },
188
+ 401: { description: "Invalid credentials", content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } } },
189
+ },
190
+ },
191
+ },
192
+
193
+ "/auth/refresh": {
194
+ post: {
195
+ tags: ["Auth"],
196
+ summary: "Refresh access token",
197
+ description: "Exchanges a valid refresh token for a new access token + new refresh token (rotation).",
198
+ parameters: [{ $ref: "#/components/parameters/TenantId" }],
199
+ requestBody: {
200
+ required: true,
201
+ content: {
202
+ "application/json": {
203
+ schema: {
204
+ type: "object",
205
+ required: ["refreshToken"],
206
+ properties: {
207
+ refreshToken: { type: "string", example: "bd5ce14f4253c157c81d546017374ee1..." },
208
+ },
209
+ },
210
+ },
211
+ },
212
+ },
213
+ responses: {
214
+ 200: { description: "New token pair", content: { "application/json": { schema: { $ref: "#/components/schemas/TokenResponse" } } } },
215
+ 401: { description: "Invalid or expired refresh token", content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } } },
216
+ },
217
+ },
218
+ },
219
+
220
+ "/auth/otp/request": {
221
+ post: {
222
+ tags: ["Auth"],
223
+ summary: "Request OTP for login",
224
+ description: "Sends a 6-digit OTP to the registered user's email. Use `/auth/otp/verify` to complete login.",
225
+ parameters: [{ $ref: "#/components/parameters/TenantId" }],
226
+ requestBody: {
227
+ required: true,
228
+ content: {
229
+ "application/json": {
230
+ schema: {
231
+ type: "object",
232
+ required: ["email"],
233
+ properties: {
234
+ email: { type: "string", format: "email", example: "user@example.com" },
235
+ },
236
+ },
237
+ },
238
+ },
239
+ },
240
+ responses: {
241
+ 200: {
242
+ description: "OTP sent",
243
+ content: {
244
+ "application/json": {
245
+ schema: {
246
+ type: "object",
247
+ properties: { message: { type: "string", example: "OTP sent to your email" } },
248
+ },
249
+ },
250
+ },
251
+ },
252
+ 400: { description: "User not found", content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } } },
253
+ },
254
+ },
255
+ },
256
+
257
+ "/auth/otp/verify": {
258
+ post: {
259
+ tags: ["Auth"],
260
+ summary: "Verify OTP and login",
261
+ description: "Verifies the OTP code and returns JWT tokens. Also marks unverified users as verified.",
262
+ parameters: [{ $ref: "#/components/parameters/TenantId" }],
263
+ requestBody: {
264
+ required: true,
265
+ content: {
266
+ "application/json": {
267
+ schema: {
268
+ type: "object",
269
+ required: ["email", "code"],
270
+ properties: {
271
+ email: { type: "string", format: "email", example: "user@example.com" },
272
+ code: { type: "string", minLength: 6, maxLength: 6, example: "482910" },
273
+ },
274
+ },
275
+ },
276
+ },
277
+ },
278
+ responses: {
279
+ 200: { description: "Login successful", content: { "application/json": { schema: { $ref: "#/components/schemas/TokenResponse" } } } },
280
+ 401: { description: "Invalid OTP", content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } } },
281
+ },
282
+ },
283
+ },
284
+
285
+ "/auth/google": {
286
+ post: {
287
+ tags: ["Auth"],
288
+ summary: "Google SSO login",
289
+ description: "Authenticates with a Google ID token. Creates the user if they don't exist.",
290
+ parameters: [{ $ref: "#/components/parameters/TenantId" }],
291
+ requestBody: {
292
+ required: true,
293
+ content: {
294
+ "application/json": {
295
+ schema: {
296
+ type: "object",
297
+ required: ["token"],
298
+ properties: {
299
+ token: { type: "string", description: "Google ID token from Sign-In SDK" },
300
+ },
301
+ },
302
+ },
303
+ },
304
+ },
305
+ responses: {
306
+ 200: { description: "Login successful", content: { "application/json": { schema: { $ref: "#/components/schemas/TokenResponse" } } } },
307
+ 401: { description: "Invalid Google token", content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } } },
308
+ },
309
+ },
310
+ },
311
+
312
+ "/auth/forgot-password": {
313
+ post: {
314
+ tags: ["Auth"],
315
+ summary: "Request password reset OTP",
316
+ description: "Sends a 6-digit OTP to the user's email for password reset. Use `/auth/reset-password` with the OTP.",
317
+ parameters: [{ $ref: "#/components/parameters/TenantId" }],
318
+ requestBody: {
319
+ required: true,
320
+ content: {
321
+ "application/json": {
322
+ schema: {
323
+ type: "object",
324
+ required: ["email"],
325
+ properties: {
326
+ email: { type: "string", format: "email", example: "user@example.com" },
327
+ },
328
+ },
329
+ },
330
+ },
331
+ },
332
+ responses: {
333
+ 200: {
334
+ description: "OTP sent",
335
+ content: {
336
+ "application/json": {
337
+ schema: {
338
+ type: "object",
339
+ properties: { message: { type: "string", example: "OTP sent to your email" } },
340
+ },
341
+ },
342
+ },
343
+ },
344
+ 400: { description: "User not found", content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } } },
345
+ },
346
+ },
347
+ },
348
+
349
+ "/auth/reset-password": {
350
+ post: {
351
+ tags: ["Auth"],
352
+ summary: "Reset password with OTP",
353
+ description: "Verifies the OTP from forgot-password and sets a new password.",
354
+ parameters: [{ $ref: "#/components/parameters/TenantId" }],
355
+ requestBody: {
356
+ required: true,
357
+ content: {
358
+ "application/json": {
359
+ schema: {
360
+ type: "object",
361
+ required: ["email", "code", "newPassword"],
362
+ properties: {
363
+ email: { type: "string", format: "email", example: "user@example.com" },
364
+ code: { type: "string", minLength: 6, maxLength: 6, example: "482910" },
365
+ newPassword: { type: "string", minLength: 8, example: "NewPass@5678" },
366
+ },
367
+ },
368
+ },
369
+ },
370
+ },
371
+ responses: {
372
+ 200: {
373
+ description: "Password reset successful",
374
+ content: {
375
+ "application/json": {
376
+ schema: {
377
+ type: "object",
378
+ properties: { message: { type: "string", example: "Password reset successfully" } },
379
+ },
380
+ },
381
+ },
382
+ },
383
+ 400: { description: "Invalid OTP or user not found", content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } } },
384
+ },
385
+ },
386
+ },
387
+
388
+ "/auth/change-password": {
389
+ post: {
390
+ tags: ["Auth"],
391
+ summary: "Change password (authenticated)",
392
+ description: "Changes the password for the currently authenticated user. Requires the current password.",
393
+ security: [{ BearerAuth: [] }],
394
+ parameters: [{ $ref: "#/components/parameters/TenantId" }],
395
+ requestBody: {
396
+ required: true,
397
+ content: {
398
+ "application/json": {
399
+ schema: {
400
+ type: "object",
401
+ required: ["oldPassword", "newPassword"],
402
+ properties: {
403
+ oldPassword: { type: "string", example: "MyPass@1234" },
404
+ newPassword: { type: "string", minLength: 8, example: "NewPass@5678" },
405
+ },
406
+ },
407
+ },
408
+ },
409
+ },
410
+ responses: {
411
+ 200: {
412
+ description: "Password changed",
413
+ content: {
414
+ "application/json": {
415
+ schema: {
416
+ type: "object",
417
+ properties: { message: { type: "string", example: "Password changed successfully" } },
418
+ },
419
+ },
420
+ },
421
+ },
422
+ 400: { description: "Incorrect old password", content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } } },
423
+ 401: { description: "Not authenticated", content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } } },
424
+ },
425
+ },
426
+ },
427
+
428
+ // ===== SESSIONS =====
429
+
430
+ "/sessions": {
431
+ get: {
432
+ tags: ["Sessions"],
433
+ summary: "List active sessions",
434
+ description: "Returns all active sessions for the authenticated user.",
435
+ security: [{ BearerAuth: [] }],
436
+ responses: {
437
+ 200: {
438
+ description: "Session list",
439
+ content: {
440
+ "application/json": {
441
+ schema: {
442
+ type: "object",
443
+ properties: {
444
+ sessions: {
445
+ type: "array",
446
+ items: { $ref: "#/components/schemas/Session" },
447
+ },
448
+ },
449
+ },
450
+ },
451
+ },
452
+ },
453
+ 401: { description: "Not authenticated", content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } } },
454
+ },
455
+ },
456
+ delete: {
457
+ tags: ["Sessions"],
458
+ summary: "Revoke all sessions",
459
+ description: "Deactivates all sessions for the authenticated user (logout everywhere).",
460
+ security: [{ BearerAuth: [] }],
461
+ responses: {
462
+ 200: {
463
+ description: "All sessions revoked",
464
+ content: {
465
+ "application/json": {
466
+ schema: {
467
+ type: "object",
468
+ properties: { message: { type: "string", example: "All sessions deactivated" } },
469
+ },
470
+ },
471
+ },
472
+ },
473
+ 401: { description: "Not authenticated", content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } } },
474
+ },
475
+ },
476
+ },
477
+
478
+ "/sessions/{id}": {
479
+ delete: {
480
+ tags: ["Sessions"],
481
+ summary: "Revoke a specific session",
482
+ description: "Deactivates a single session by ID.",
483
+ security: [{ BearerAuth: [] }],
484
+ parameters: [
485
+ {
486
+ in: "path",
487
+ name: "id",
488
+ required: true,
489
+ schema: { type: "string" },
490
+ description: "Session ID",
491
+ },
492
+ ],
493
+ responses: {
494
+ 200: {
495
+ description: "Session revoked",
496
+ content: {
497
+ "application/json": {
498
+ schema: {
499
+ type: "object",
500
+ properties: { message: { type: "string", example: "Session deactivated" } },
501
+ },
502
+ },
503
+ },
504
+ },
505
+ 401: { description: "Not authenticated", content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } } },
506
+ },
507
+ },
508
+ },
509
+ },
510
+ };
511
+
512
+ export function setupSwagger(app: Express): void {
513
+ app.use(
514
+ "/docs",
515
+ swaggerUi.serve,
516
+ swaggerUi.setup(swaggerDocument, {
517
+ customCss: ".swagger-ui .topbar { display: none }",
518
+ customSiteTitle: "SecurePool API Docs",
519
+ swaggerOptions: {
520
+ persistAuthorization: true,
521
+ },
522
+ })
523
+ );
524
+
525
+ // Serve raw JSON spec
526
+ app.get("/docs.json", (_req, res) => {
527
+ res.json(swaggerDocument);
528
+ });
529
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "rootDir": "src",
5
+ "outDir": "dist"
6
+ },
7
+ "include": ["src"]
8
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "name": "@securepool/application",
3
+ "version": "1.0.0",
4
+ "main": "dist/index.js",
5
+ "types": "dist/index.d.ts",
6
+ "scripts": {
7
+ "build": "tsc",
8
+ "clean": "rm -rf dist"
9
+ },
10
+ "dependencies": {
11
+ "@securepool/core": "1.0.0"
12
+ },
13
+ "devDependencies": {
14
+ "typescript": "^5.5.0"
15
+ }
16
+ }
@@ -0,0 +1,17 @@
1
+ // Interfaces
2
+ export { IUserRepository } from "./interfaces/IUserRepository";
3
+ export { ITokenRepository } from "./interfaces/ITokenRepository";
4
+ export { IOtpRepository } from "./interfaces/IOtpRepository";
5
+ export { ISessionRepository } from "./interfaces/ISessionRepository";
6
+ export { IAuditLogRepository } from "./interfaces/IAuditLogRepository";
7
+ export { IRoleRepository } from "./interfaces/IRoleRepository";
8
+ export { IPasswordHasher } from "./interfaces/IPasswordHasher";
9
+ export { ITokenService } from "./interfaces/ITokenService";
10
+ export { IOtpService } from "./interfaces/IOtpService";
11
+ export { IGoogleAuthService } from "./interfaces/IGoogleAuthService";
12
+ export { IAuthPlugin } from "./interfaces/IAuthPlugin";
13
+ export { IEmailService } from "./interfaces/IEmailService";
14
+
15
+ // Services
16
+ export { AuthService } from "./services/AuthService";
17
+ export { RefreshTokenService } from "./services/RefreshTokenService";
@@ -0,0 +1,6 @@
1
+ import { AuditLog } from "@securepool/core";
2
+
3
+ export interface IAuditLogRepository {
4
+ log(entry: AuditLog): Promise<void>;
5
+ findByUserId(userId: string): Promise<AuditLog[]>;
6
+ }
@@ -0,0 +1,4 @@
1
+ export interface IAuthPlugin {
2
+ name: string;
3
+ execute(data: unknown): Promise<unknown>;
4
+ }
@@ -0,0 +1,3 @@
1
+ export interface IEmailService {
2
+ sendOtp(to: string, code: string): Promise<void>;
3
+ }
@@ -0,0 +1,3 @@
1
+ export interface IGoogleAuthService {
2
+ verifyToken(token: string): Promise<{ email: string; name: string; googleId: string }>;
3
+ }
@@ -0,0 +1,8 @@
1
+ import { OtpCode } from "@securepool/core";
2
+
3
+ export interface IOtpRepository {
4
+ save(otp: OtpCode): Promise<void>;
5
+ findLatest(userId: string): Promise<OtpCode | null>;
6
+ update(otp: OtpCode): Promise<void>;
7
+ deleteAllForUser(userId: string): Promise<void>;
8
+ }
@@ -0,0 +1,4 @@
1
+ export interface IOtpService {
2
+ generate(userId: string, metadata?: Record<string, string>): Promise<string>;
3
+ verify(userId: string, code: string): Promise<{ valid: boolean; metadata?: Record<string, string> }>;
4
+ }
@@ -0,0 +1,4 @@
1
+ export interface IPasswordHasher {
2
+ hash(password: string): Promise<string>;
3
+ compare(password: string, hash: string): Promise<boolean>;
4
+ }
@@ -0,0 +1,8 @@
1
+ import { Role, UserRole } from "@securepool/core";
2
+
3
+ export interface IRoleRepository {
4
+ findById(id: string): Promise<Role | null>;
5
+ findByName(name: string): Promise<Role | null>;
6
+ assignRole(userRole: UserRole): Promise<void>;
7
+ getUserRoles(userId: string): Promise<Role[]>;
8
+ }
@@ -0,0 +1,8 @@
1
+ import { Session } from "@securepool/core";
2
+
3
+ export interface ISessionRepository {
4
+ create(session: Session): Promise<void>;
5
+ findByUserId(userId: string): Promise<Session[]>;
6
+ deactivate(sessionId: string): Promise<void>;
7
+ deactivateAllForUser(userId: string): Promise<void>;
8
+ }
@@ -0,0 +1,9 @@
1
+ import { RefreshToken } from "@securepool/core";
2
+
3
+ export interface ITokenRepository {
4
+ save(token: RefreshToken): Promise<void>;
5
+ findByTokenHash(tokenHash: string): Promise<RefreshToken | null>;
6
+ findActiveByUserId(userId: string): Promise<RefreshToken[]>;
7
+ revoke(tokenId: string): Promise<void>;
8
+ revokeAllForUser(userId: string): Promise<void>;
9
+ }
@@ -0,0 +1,5 @@
1
+ export interface ITokenService {
2
+ generateAccessToken(userId: string, tenantId: string): Promise<string>;
3
+ generateRefreshToken(userId: string): Promise<string>;
4
+ verifyAccessToken(token: string): Promise<{ sub: string; tenantId: string }>;
5
+ }
@@ -0,0 +1,8 @@
1
+ import { User } from "@securepool/core";
2
+
3
+ export interface IUserRepository {
4
+ findById(id: string): Promise<User | null>;
5
+ findByEmail(email: string, tenantId: string): Promise<User | null>;
6
+ create(user: User): Promise<void>;
7
+ update(user: User): Promise<void>;
8
+ }