cca-auth-module 0.2.1 → 0.2.21
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/README.md +385 -395
- package/dist/application/useCase/LogoutUseCase.d.ts +1 -1
- package/dist/domain/interfaces/IAuthService.d.ts +2 -2
- package/dist/domain/interfaces/IDecodedToken.d.ts +1 -0
- package/dist/domain/interfaces/IJwtAuth.d.ts +4 -4
- package/dist/domain/interfaces/IJwtPayload.d.ts +1 -0
- package/dist/index.d.mts +7 -6
- package/dist/index.d.ts +7 -6
- package/dist/index.js +138 -60
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +138 -60
- package/dist/index.mjs.map +1 -1
- package/dist/infrastructure/repository/AuthRepository.d.ts +2 -1
- package/dist/infrastructure/services/JwtAuthService.d.ts +1 -2
- package/package.json +7 -4
package/README.md
CHANGED
|
@@ -1,395 +1,385 @@
|
|
|
1
|
-
# Auth Module
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
```
|
|
22
|
-
{
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
###
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
"
|
|
76
|
-
"
|
|
77
|
-
|
|
78
|
-
"
|
|
79
|
-
"
|
|
80
|
-
|
|
81
|
-
"
|
|
82
|
-
"
|
|
83
|
-
"
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
```json
|
|
108
|
-
{
|
|
109
|
-
"success": true,
|
|
110
|
-
"message": "
|
|
111
|
-
"data": {
|
|
112
|
-
"
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
"
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
{
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
"
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
```
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
"
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
**POST** `/auth/2fa/verify`
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
```json
|
|
301
|
-
{
|
|
302
|
-
"success": true,
|
|
303
|
-
"message": "
|
|
304
|
-
"data": {
|
|
305
|
-
"token": "accessToken",
|
|
306
|
-
"refreshToken": "refreshToken",
|
|
307
|
-
"user": {
|
|
308
|
-
"id": "userId",
|
|
309
|
-
"email": "user@example.com",
|
|
310
|
-
"name": "User Name",
|
|
311
|
-
"role": "
|
|
312
|
-
},
|
|
313
|
-
"auth": {
|
|
314
|
-
"hasAccessToken": true,
|
|
315
|
-
"
|
|
316
|
-
"status": "
|
|
317
|
-
"verified": true
|
|
318
|
-
}
|
|
319
|
-
},
|
|
320
|
-
"meta": {
|
|
321
|
-
"recommendation": "You're fully authenticated",
|
|
322
|
-
"redirectTo": "/"
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
```
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
```
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
```
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
---
|
|
388
|
-
|
|
389
|
-
## License
|
|
390
|
-
|
|
391
|
-
This module is released under the [MIT License](LICENSE).
|
|
392
|
-
|
|
393
|
-
---
|
|
394
|
-
|
|
395
|
-
This documentation provides an overview of the available endpoints and helper methods for authentication. For further details on business logic and DTO structures, please refer to the inline comments and source code within the module.
|
|
1
|
+
# CCA Auth Module
|
|
2
|
+
|
|
3
|
+
Authentication + 2FA module for CCA applications. Provides a controller, use cases, and container wiring for login, registration, refresh, and 2FA flows.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Login and admin login
|
|
8
|
+
- Registration with role support
|
|
9
|
+
- Refresh token rotation
|
|
10
|
+
- Two-factor setup, enable, verify, disable
|
|
11
|
+
- Middleware to require completed 2FA
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pnpm add cca-auth-module
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
import { authConfig, createAuthContainer } from "cca-auth-module";
|
|
23
|
+
|
|
24
|
+
authConfig(async () => ({
|
|
25
|
+
accessTokenSecret: process.env.ACCESS_TOKEN_SECRET!,
|
|
26
|
+
refreshTokenSecret: process.env.REFRESH_TOKEN_SECRET!,
|
|
27
|
+
accessTokenExpiry: "15m",
|
|
28
|
+
refreshTokenExpiry: "30d",
|
|
29
|
+
adminSecretPassword: process.env.ADMIN_SECRET_PASSWORD!,
|
|
30
|
+
app_name: "MyApp",
|
|
31
|
+
secretLength: "20",
|
|
32
|
+
tokenWindow: "1",
|
|
33
|
+
isDevelopment: false,
|
|
34
|
+
}));
|
|
35
|
+
|
|
36
|
+
const { authController, requireComplete2FA } = await createAuthContainer(database);
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Configuration
|
|
40
|
+
|
|
41
|
+
The module reads configuration via `authConfig` and `ConfigSource`.
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
export interface IConfig {
|
|
45
|
+
accessTokenSecret: string;
|
|
46
|
+
refreshTokenSecret: string;
|
|
47
|
+
accessTokenExpiry: string;
|
|
48
|
+
refreshTokenExpiry: string;
|
|
49
|
+
adminSecretPassword: string;
|
|
50
|
+
app_name: string;
|
|
51
|
+
secretLength: string;
|
|
52
|
+
tokenWindow: string;
|
|
53
|
+
isDevelopment: boolean;
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## API Endpoints
|
|
58
|
+
|
|
59
|
+
### 1) Login
|
|
60
|
+
|
|
61
|
+
**POST** `/auth/login`
|
|
62
|
+
|
|
63
|
+
Request:
|
|
64
|
+
```json
|
|
65
|
+
{
|
|
66
|
+
"email": "user@example.com",
|
|
67
|
+
"password": "Password1!"
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Response:
|
|
72
|
+
```json
|
|
73
|
+
{
|
|
74
|
+
"success": true,
|
|
75
|
+
"message": "Login successful",
|
|
76
|
+
"data": {
|
|
77
|
+
"accessToken": "string",
|
|
78
|
+
"userId": "string",
|
|
79
|
+
"expiresAt": 1738166400,
|
|
80
|
+
"auth": {
|
|
81
|
+
"hasAccessToken": true,
|
|
82
|
+
"enabled": false,
|
|
83
|
+
"status": "pending_verification",
|
|
84
|
+
"verified": false
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
"meta": {
|
|
88
|
+
"timestamp": "2026-01-29T10:00:00.000Z"
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### 2) Admin Login
|
|
94
|
+
|
|
95
|
+
**POST** `/auth/admin-login`
|
|
96
|
+
|
|
97
|
+
Request:
|
|
98
|
+
```json
|
|
99
|
+
{
|
|
100
|
+
"email": "admin@example.com",
|
|
101
|
+
"password": "Password1!",
|
|
102
|
+
"adminPassword": "AdminSecret"
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Response:
|
|
107
|
+
```json
|
|
108
|
+
{
|
|
109
|
+
"success": true,
|
|
110
|
+
"message": "Admin login successful",
|
|
111
|
+
"data": {
|
|
112
|
+
"accessToken": "string",
|
|
113
|
+
"userId": "string",
|
|
114
|
+
"expiresAt": 1738166400,
|
|
115
|
+
"auth": {
|
|
116
|
+
"hasAccessToken": true,
|
|
117
|
+
"enabled": true,
|
|
118
|
+
"status": "pending_verification",
|
|
119
|
+
"verified": false
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### 3) Logout
|
|
126
|
+
|
|
127
|
+
**POST** `/auth/logout`
|
|
128
|
+
|
|
129
|
+
Headers:
|
|
130
|
+
```
|
|
131
|
+
Authorization: Bearer <accessToken>
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Request:
|
|
135
|
+
```json
|
|
136
|
+
{}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Response:
|
|
140
|
+
```json
|
|
141
|
+
{
|
|
142
|
+
"success": true,
|
|
143
|
+
"message": "Logged out successfully",
|
|
144
|
+
"data": {
|
|
145
|
+
"auth": {
|
|
146
|
+
"hasAccessToken": false,
|
|
147
|
+
"enabled": false,
|
|
148
|
+
"status": "logged_out",
|
|
149
|
+
"verified": false
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### 4) Register
|
|
156
|
+
|
|
157
|
+
**POST** `/auth/register`
|
|
158
|
+
|
|
159
|
+
Request:
|
|
160
|
+
```json
|
|
161
|
+
{
|
|
162
|
+
"email": "newuser@example.com",
|
|
163
|
+
"name": "New User",
|
|
164
|
+
"password": "Password1!",
|
|
165
|
+
"role": "USER",
|
|
166
|
+
"adminPassword": "optional-if-role-admin"
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Response:
|
|
171
|
+
```json
|
|
172
|
+
{
|
|
173
|
+
"success": true,
|
|
174
|
+
"message": "User registered successfully",
|
|
175
|
+
"data": {
|
|
176
|
+
"auth": {
|
|
177
|
+
"hasAccessToken": false,
|
|
178
|
+
"enabled": false,
|
|
179
|
+
"status": "registered",
|
|
180
|
+
"verified": false
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
"meta": {
|
|
184
|
+
"status": true
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### 5) Refresh Token
|
|
190
|
+
|
|
191
|
+
**POST** `/auth/refresh-token`
|
|
192
|
+
|
|
193
|
+
Request:
|
|
194
|
+
```json
|
|
195
|
+
{
|
|
196
|
+
"refreshToken": "yourRefreshToken"
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Response:
|
|
201
|
+
```json
|
|
202
|
+
{
|
|
203
|
+
"success": true,
|
|
204
|
+
"message": "Token refreshed successfully",
|
|
205
|
+
"data": {
|
|
206
|
+
"accessToken": "newAccessToken",
|
|
207
|
+
"refreshToken": "newRefreshToken",
|
|
208
|
+
"auth": {
|
|
209
|
+
"hasAccessToken": true,
|
|
210
|
+
"enabled": false,
|
|
211
|
+
"status": "basic_auth",
|
|
212
|
+
"verified": false
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### 6) 2FA Setup
|
|
219
|
+
|
|
220
|
+
**POST** `/auth/2fa/setup`
|
|
221
|
+
|
|
222
|
+
Headers:
|
|
223
|
+
```
|
|
224
|
+
Authorization: Bearer <accessToken>
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Response:
|
|
228
|
+
```json
|
|
229
|
+
{
|
|
230
|
+
"success": true,
|
|
231
|
+
"message": "Two-factor authentication setup initiated",
|
|
232
|
+
"data": {
|
|
233
|
+
"qrCode": "data:image/png;base64,...",
|
|
234
|
+
"auth": {
|
|
235
|
+
"hasAccessToken": true,
|
|
236
|
+
"enabled": false,
|
|
237
|
+
"status": "needs_setup"
|
|
238
|
+
}
|
|
239
|
+
},
|
|
240
|
+
"meta": {
|
|
241
|
+
"nextStep": "Scan the QR code and enter your first code to verify",
|
|
242
|
+
"redirectTo": "/2fa-enable"
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### 7) Enable 2FA
|
|
248
|
+
|
|
249
|
+
**POST** `/auth/2fa/enable`
|
|
250
|
+
|
|
251
|
+
Headers:
|
|
252
|
+
```
|
|
253
|
+
Authorization: Bearer <accessToken>
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
Request:
|
|
257
|
+
```json
|
|
258
|
+
{
|
|
259
|
+
"token": "2faToken"
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
Response:
|
|
264
|
+
```json
|
|
265
|
+
{
|
|
266
|
+
"success": true,
|
|
267
|
+
"message": "Two-factor authentication enabled",
|
|
268
|
+
"data": {
|
|
269
|
+
"enabledAt": "2026-01-29T10:00:00.000Z",
|
|
270
|
+
"auth": {
|
|
271
|
+
"hasAccessToken": true,
|
|
272
|
+
"enabled": true,
|
|
273
|
+
"status": "pending_verification"
|
|
274
|
+
}
|
|
275
|
+
},
|
|
276
|
+
"meta": {
|
|
277
|
+
"nextStep": "Proceed to verify with a valid 2FA token",
|
|
278
|
+
"redirectTo": "/verify-2fa"
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### 8) Verify 2FA
|
|
284
|
+
|
|
285
|
+
**POST** `/auth/2fa/verify`
|
|
286
|
+
|
|
287
|
+
Headers:
|
|
288
|
+
```
|
|
289
|
+
Authorization: Bearer <accessToken>
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
Request:
|
|
293
|
+
```json
|
|
294
|
+
{
|
|
295
|
+
"token": "2faVerificationToken"
|
|
296
|
+
}
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
Response:
|
|
300
|
+
```json
|
|
301
|
+
{
|
|
302
|
+
"success": true,
|
|
303
|
+
"message": "Two-factor authentication verified successfully",
|
|
304
|
+
"data": {
|
|
305
|
+
"token": "accessToken",
|
|
306
|
+
"refreshToken": "refreshToken",
|
|
307
|
+
"user": {
|
|
308
|
+
"id": "userId",
|
|
309
|
+
"email": "user@example.com",
|
|
310
|
+
"name": "User Name",
|
|
311
|
+
"role": "USER"
|
|
312
|
+
},
|
|
313
|
+
"auth": {
|
|
314
|
+
"hasAccessToken": true,
|
|
315
|
+
"enabled": true,
|
|
316
|
+
"status": "full_auth",
|
|
317
|
+
"verified": true
|
|
318
|
+
}
|
|
319
|
+
},
|
|
320
|
+
"meta": {
|
|
321
|
+
"recommendation": "You're fully authenticated",
|
|
322
|
+
"redirectTo": "/"
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
### 9) Disable 2FA
|
|
328
|
+
|
|
329
|
+
**POST** `/auth/2fa/disable`
|
|
330
|
+
|
|
331
|
+
Headers:
|
|
332
|
+
```
|
|
333
|
+
Authorization: Bearer <accessToken>
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
Request:
|
|
337
|
+
```json
|
|
338
|
+
{
|
|
339
|
+
"token": "current2faToken"
|
|
340
|
+
}
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
Response:
|
|
344
|
+
```json
|
|
345
|
+
{
|
|
346
|
+
"success": true,
|
|
347
|
+
"message": "Two-factor authentication disabled",
|
|
348
|
+
"data": {
|
|
349
|
+
"disabledAt": "2026-01-29T10:00:00.000Z",
|
|
350
|
+
"auth": {
|
|
351
|
+
"hasAccessToken": true,
|
|
352
|
+
"enabled": false,
|
|
353
|
+
"status": "basic_auth",
|
|
354
|
+
"verified": false
|
|
355
|
+
}
|
|
356
|
+
},
|
|
357
|
+
"meta": {
|
|
358
|
+
"securityNote": "Account now relies only on password. Re-enable 2FA for better security.",
|
|
359
|
+
"redirectTo": "/login"
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
## Middleware
|
|
365
|
+
|
|
366
|
+
Use `RequireComplete2FA` to block routes until the user completes 2FA. It expects a JWT with `twoFactorAuthenticated: true`.
|
|
367
|
+
|
|
368
|
+
```ts
|
|
369
|
+
app.get("/secure", requireComplete2FA.execute, handler);
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
## Status Codes and Messages
|
|
373
|
+
|
|
374
|
+
- Status codes are defined in `src/presentation/constants/constants.ts`
|
|
375
|
+
- Error handling uses module errors from `src/utils/Errors.ts`
|
|
376
|
+
|
|
377
|
+
## Notes
|
|
378
|
+
|
|
379
|
+
- All token endpoints must be served over HTTPS in production.
|
|
380
|
+
- Refresh tokens are rotated and validated against stored values.
|
|
381
|
+
- Admin registration requires a valid `adminSecretPassword`.
|
|
382
|
+
|
|
383
|
+
## License
|
|
384
|
+
|
|
385
|
+
MIT
|