@ackplus/nest-auth 1.1.18 → 1.1.19

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 (27) hide show
  1. package/package.json +1 -1
  2. package/src/lib/admin-console/static/index.html +697 -177
  3. package/src/lib/auth/controllers/mfa.controller.js +5 -5
  4. package/src/lib/auth/dto/responses/mfa-status.response.dto.d.ts +2 -2
  5. package/src/lib/auth/dto/responses/mfa-status.response.dto.d.ts.map +1 -1
  6. package/src/lib/auth/dto/responses/mfa-status.response.dto.js +5 -5
  7. package/src/lib/auth/guards/auth.guard.d.ts.map +1 -1
  8. package/src/lib/auth/guards/auth.guard.js +28 -13
  9. package/src/lib/auth/services/auth.service.d.ts.map +1 -1
  10. package/src/lib/auth/services/auth.service.js +188 -61
  11. package/src/lib/auth/services/mfa.service.d.ts.map +1 -1
  12. package/src/lib/auth/services/mfa.service.js +19 -8
  13. package/src/lib/auth.constants.d.ts +178 -8
  14. package/src/lib/auth.constants.d.ts.map +1 -1
  15. package/src/lib/auth.constants.js +139 -10
  16. package/src/lib/core/interfaces/auth-module-options.interface.d.ts +170 -0
  17. package/src/lib/core/interfaces/auth-module-options.interface.d.ts.map +1 -1
  18. package/src/lib/core/interfaces/session-options.interface.d.ts +52 -0
  19. package/src/lib/core/interfaces/session-options.interface.d.ts.map +1 -1
  20. package/src/lib/core/interfaces/token-payload.interface.d.ts +14 -6
  21. package/src/lib/core/interfaces/token-payload.interface.d.ts.map +1 -1
  22. package/src/lib/session/services/session-manager.service.d.ts +3 -3
  23. package/src/lib/session/services/session-manager.service.d.ts.map +1 -1
  24. package/src/lib/session/services/session-manager.service.js +27 -17
  25. package/src/lib/user/services/user.service.d.ts +3 -1
  26. package/src/lib/user/services/user.service.d.ts.map +1 -1
  27. package/src/lib/user/services/user.service.js +17 -4
@@ -64,7 +64,10 @@ let AuthService = class AuthService {
64
64
  try {
65
65
  const config = this.authConfigService.getConfig();
66
66
  if (config.registration?.enabled === false) {
67
- throw new common_1.ForbiddenException('Registration is disabled');
67
+ throw new common_1.ForbiddenException({
68
+ message: 'Registration is disabled',
69
+ code: auth_constants_1.ERROR_CODES.REGISTRATION_DISABLED,
70
+ });
68
71
  }
69
72
  const { email, phone, password } = input;
70
73
  let { tenantId = null } = input;
@@ -73,7 +76,10 @@ let AuthService = class AuthService {
73
76
  this.debugLogger.logAuthOperation('signup', 'email|phone', undefined, { email, phone, resolvedTenantId: tenantId });
74
77
  if (!email && !phone) {
75
78
  this.debugLogger.error('Signup failed: Neither email nor phone provided', 'AuthService');
76
- throw new common_1.BadRequestException('Either email or phone must be provided');
79
+ throw new common_1.BadRequestException({
80
+ message: 'Either email or phone must be provided',
81
+ code: auth_constants_1.ERROR_CODES.EMAIL_OR_PHONE_REQUIRED,
82
+ });
77
83
  }
78
84
  let provider = null;
79
85
  let providerUserId = null;
@@ -87,17 +93,26 @@ let AuthService = class AuthService {
87
93
  }
88
94
  if (!provider) {
89
95
  this.debugLogger.error('Provider not found for signup', 'AuthService', { email: !!email, phone: !!phone });
90
- throw new common_1.InternalServerErrorException('Phone or email authentication is not enabled');
96
+ throw new common_1.InternalServerErrorException({
97
+ message: 'Phone or email authentication is not enabled',
98
+ code: auth_constants_1.ERROR_CODES.PROVIDER_NOT_FOUND,
99
+ });
91
100
  }
92
101
  this.debugLogger.debug('Checking for existing identity', 'AuthService', { providerUserId });
93
102
  const identity = await provider.findIdentity(providerUserId);
94
103
  if (identity) {
95
104
  this.debugLogger.warn('Identity already exists', 'AuthService', { email: !!email, phone: !!phone, tenantId });
96
105
  if (email) {
97
- throw new common_1.BadRequestException('Email already exists in this tenant');
106
+ throw new common_1.BadRequestException({
107
+ message: 'Email already exists in this tenant',
108
+ code: auth_constants_1.ERROR_CODES.EMAIL_ALREADY_EXISTS,
109
+ });
98
110
  }
99
111
  if (phone) {
100
- throw new common_1.BadRequestException('Phone number already exists in this tenant');
112
+ throw new common_1.BadRequestException({
113
+ message: 'Phone number already exists in this tenant',
114
+ code: auth_constants_1.ERROR_CODES.PHONE_ALREADY_EXISTS,
115
+ });
101
116
  }
102
117
  }
103
118
  this.debugLogger.debug('Creating new user', 'AuthService', { email: !!email, phone: !!phone, tenantId });
@@ -130,11 +145,17 @@ let AuthService = class AuthService {
130
145
  isRequiresMfa
131
146
  }));
132
147
  this.debugLogger.logFunctionExit('signup', 'AuthService', { userId: user.id, isRequiresMfa });
133
- return {
148
+ // Build default response
149
+ let response = {
134
150
  accessToken: tokens.accessToken,
135
151
  refreshToken: tokens.refreshToken,
136
152
  isRequiresMfa: isRequiresMfa,
137
153
  };
154
+ // Apply auth.transformResponse hook if configured
155
+ if (config.auth?.transformResponse) {
156
+ response = await config.auth.transformResponse(response, user, session);
157
+ }
158
+ return response;
138
159
  }
139
160
  catch (error) {
140
161
  this.debugLogger.logError(error, 'signup', { email: input.email, phone: input.phone });
@@ -150,18 +171,27 @@ let AuthService = class AuthService {
150
171
  this.debugLogger.logAuthOperation('login', providerName, undefined, { resolvedTenantId: tenantId, createUserIfNotExists });
151
172
  const provider = this.authProviderRegistry.getProvider(providerName);
152
173
  if (!provider) {
153
- throw new common_1.UnauthorizedException('Invalid authentication providerName or provider is not enabled');
174
+ throw new common_1.UnauthorizedException({
175
+ message: 'Invalid authentication providerName or provider is not enabled',
176
+ code: auth_constants_1.ERROR_CODES.INVALID_PROVIDER,
177
+ });
154
178
  }
155
179
  const requiredFields = provider.getRequiredFields();
156
180
  if (!requiredFields.every(field => credentials[field])) {
157
- throw new common_1.BadRequestException(`Missing ${requiredFields.join(', ')} required fields`);
181
+ throw new common_1.BadRequestException({
182
+ message: `Missing ${requiredFields.join(', ')} required fields`,
183
+ code: auth_constants_1.ERROR_CODES.MISSING_REQUIRED_FIELDS,
184
+ });
158
185
  }
159
186
  const authProviderUser = await provider.validate(credentials);
160
187
  const identity = await provider.findIdentity(authProviderUser.userId);
161
188
  let user = identity?.user || null;
162
189
  if (!user) {
163
190
  if (!createUserIfNotExists) {
164
- throw new common_1.UnauthorizedException('Invalid credentials');
191
+ throw new common_1.UnauthorizedException({
192
+ message: 'Invalid credentials',
193
+ code: auth_constants_1.ERROR_CODES.INVALID_CREDENTIALS,
194
+ });
165
195
  }
166
196
  // Create new user if not exists and link to provider
167
197
  user = await this.handleSocialLogin(provider, authProviderUser, tenantId);
@@ -169,19 +199,15 @@ let AuthService = class AuthService {
169
199
  if (user.isActive === false) {
170
200
  throw new common_1.UnauthorizedException({
171
201
  message: 'Your account is suspended, please contact support',
172
- code: auth_constants_1.USER_NOT_ACTIVE_ERROR,
202
+ code: auth_constants_1.ERROR_CODES.ACCOUNT_INACTIVE,
173
203
  });
174
204
  }
175
- user = await this.getUserWithRolesAndPermissions(user.id);
176
- const session = await this.sessionManager.createSessionFromUser(user);
177
- const tokens = await this.generateTokensFromSession(session);
178
205
  let isRequiresMfa = await this.mfaService.isRequiresMfa(user.id);
206
+ user.isMfaEnabled = isRequiresMfa;
207
+ user = await this.getUserWithRolesAndPermissions(user.id);
208
+ let session = await this.sessionManager.createSessionFromUser(user);
179
209
  // Check for trusted device cookie or header if MFA is required
180
210
  if (isRequiresMfa) {
181
- // Set Mfa enbale if requred for all user, set in properly in session
182
- await this.sessionManager.updateSession(session.id, {
183
- data: { ...session.data, isMfaEnabled: true }
184
- });
185
211
  const trustCookieName = auth_config_service_1.AuthConfigService.getOptions().mfa?.trustDeviceStorageName || auth_constants_1.NEST_AUTH_TRUST_DEVICE_KEY;
186
212
  const req = request_context_1.RequestContext.currentRequest();
187
213
  let trustToken = cookie_helper_1.CookieHelper.get(req, trustCookieName);
@@ -194,12 +220,13 @@ let AuthService = class AuthService {
194
220
  if (isTrusted) {
195
221
  isRequiresMfa = false;
196
222
  // Update session to indicate MFA is verified by trust
197
- await this.sessionManager.updateSession(session.id, {
223
+ session = await this.sessionManager.updateSession(session.id, {
198
224
  data: { ...session.data, isMfaVerified: true }
199
225
  });
200
226
  }
201
227
  }
202
228
  }
229
+ const tokens = await this.generateTokensFromSession(session);
203
230
  // Emit login event
204
231
  await this.eventEmitter.emitAsync(auth_constants_1.NestAuthEvents.LOGGED_IN, new user_logged_in_event_1.UserLoggedInEvent({
205
232
  user,
@@ -210,11 +237,18 @@ let AuthService = class AuthService {
210
237
  tokens,
211
238
  isRequiresMfa
212
239
  }));
213
- return {
240
+ // Build default response
241
+ let response = {
214
242
  accessToken: tokens.accessToken,
215
243
  refreshToken: tokens.refreshToken,
216
244
  isRequiresMfa: isRequiresMfa,
217
245
  };
246
+ // Apply auth.transformResponse hook if configured
247
+ const config = this.authConfigService.getConfig();
248
+ if (config.auth?.transformResponse) {
249
+ response = await config.auth.transformResponse(response, user, session);
250
+ }
251
+ return response;
218
252
  }
219
253
  async verify2fa(input) {
220
254
  this.debugLogger.logFunctionEntry('verify2fa', 'AuthService', { method: input.method });
@@ -224,7 +258,7 @@ let AuthService = class AuthService {
224
258
  this.debugLogger.error('Session not found for 2FA verification', 'AuthService');
225
259
  throw new common_1.UnauthorizedException({
226
260
  message: 'Session not found',
227
- code: auth_constants_1.SESSION_NOT_FOUND_ERROR,
261
+ code: auth_constants_1.ERROR_CODES.SESSION_NOT_FOUND,
228
262
  });
229
263
  }
230
264
  this.debugLogger.debug('Verifying MFA code', 'AuthService', { userId: session.userId, method: input.method });
@@ -233,7 +267,7 @@ let AuthService = class AuthService {
233
267
  this.debugLogger.warn('Invalid MFA code provided', 'AuthService', { userId: session.userId, method: input.method });
234
268
  throw new common_1.UnauthorizedException({
235
269
  message: 'Invalid MFA code',
236
- code: auth_constants_1.INVALID_MFA_EXCEPTION_CODE,
270
+ code: auth_constants_1.ERROR_CODES.MFA_CODE_INVALID,
237
271
  });
238
272
  }
239
273
  this.debugLogger.debug('Updating session with MFA verification', 'AuthService', { sessionId: session.id });
@@ -276,7 +310,10 @@ let AuthService = class AuthService {
276
310
  async send2faCode(userId, method) {
277
311
  const user = await this.userRepository.findOne({ where: { id: userId } });
278
312
  if (!user) {
279
- throw new common_1.UnauthorizedException('User not found');
313
+ throw new common_1.UnauthorizedException({
314
+ message: 'User not found',
315
+ code: auth_constants_1.ERROR_CODES.USER_NOT_FOUND,
316
+ });
280
317
  }
281
318
  await this.mfaService.sendMfaCode(user.id, method);
282
319
  return true;
@@ -309,7 +346,7 @@ let AuthService = class AuthService {
309
346
  this.debugLogger.error('No refresh token provided', 'AuthService');
310
347
  throw new common_1.UnauthorizedException({
311
348
  message: 'No refresh token provided',
312
- code: auth_constants_1.REFRESH_TOKEN_INVALID,
349
+ code: auth_constants_1.ERROR_CODES.REFRESH_TOKEN_INVALID,
313
350
  });
314
351
  }
315
352
  this.debugLogger.debug('Verifying refresh token', 'AuthService');
@@ -321,20 +358,18 @@ let AuthService = class AuthService {
321
358
  this.debugLogger.warn('Invalid or expired refresh token', 'AuthService');
322
359
  throw new common_1.UnauthorizedException({
323
360
  message: 'Invalid or expired refresh token',
324
- code: auth_constants_1.REFRESH_TOKEN_EXPIRED,
361
+ code: auth_constants_1.ERROR_CODES.REFRESH_TOKEN_EXPIRED,
325
362
  });
326
363
  }
327
364
  const session = await this.sessionManager.getSession(payload.sessionId);
328
365
  if (!session) {
329
366
  throw new common_1.UnauthorizedException({
330
367
  message: 'Invalid refresh token',
331
- code: auth_constants_1.REFRESH_TOKEN_INVALID,
368
+ code: auth_constants_1.ERROR_CODES.REFRESH_TOKEN_INVALID,
332
369
  });
333
370
  }
334
- // Generate new session
335
- const newSession = await this.sessionManager.createSessionFromSession(session);
336
- // Revoke old session
337
- await this.sessionManager.revokeSession(session.id);
371
+ // Refresh existing session
372
+ const newSession = await this.sessionManager.refreshSession(session);
338
373
  // Generate new tokens
339
374
  this.debugLogger.debug('Generating new tokens from refreshed session', 'AuthService', { sessionId: newSession.id });
340
375
  const tokens = await this.generateTokensFromSession(newSession);
@@ -358,20 +393,32 @@ let AuthService = class AuthService {
358
393
  try {
359
394
  const currentUser = request_context_1.RequestContext.currentUser();
360
395
  if (!currentUser?.id) {
361
- throw new common_1.UnauthorizedException('User not found');
396
+ throw new common_1.UnauthorizedException({
397
+ message: 'User not found',
398
+ code: auth_constants_1.ERROR_CODES.USER_NOT_FOUND,
399
+ });
362
400
  }
363
401
  const user = await this.userRepository.findOne({
364
402
  where: { id: currentUser.id },
365
403
  });
366
404
  if (!user) {
367
- throw new common_1.UnauthorizedException('User not found');
405
+ throw new common_1.UnauthorizedException({
406
+ message: 'User not found',
407
+ code: auth_constants_1.ERROR_CODES.USER_NOT_FOUND,
408
+ });
368
409
  }
369
410
  const isValid = await user.validatePassword(input.currentPassword);
370
411
  if (!isValid) {
371
- throw new common_1.BadRequestException('Current password is incorrect');
412
+ throw new common_1.BadRequestException({
413
+ message: 'Current password is incorrect',
414
+ code: auth_constants_1.ERROR_CODES.CURRENT_PASSWORD_INCORRECT,
415
+ });
372
416
  }
373
417
  if (input.currentPassword === input.newPassword) {
374
- throw new common_1.BadRequestException('New password must be different from the current password');
418
+ throw new common_1.BadRequestException({
419
+ message: 'New password must be different from the current password',
420
+ code: auth_constants_1.ERROR_CODES.NEW_PASSWORD_SAME_AS_CURRENT,
421
+ });
375
422
  }
376
423
  await user.setPassword(input.newPassword);
377
424
  await this.userRepository.save(user);
@@ -407,17 +454,29 @@ let AuthService = class AuthService {
407
454
  provider = this.authProviderRegistry.getProvider(auth_constants_1.EMAIL_AUTH_PROVIDER);
408
455
  }
409
456
  else {
410
- throw new common_1.BadRequestException('Either email or phone must be provided');
457
+ throw new common_1.BadRequestException({
458
+ message: 'Either email or phone must be provided',
459
+ code: auth_constants_1.ERROR_CODES.EMAIL_OR_PHONE_REQUIRED,
460
+ });
411
461
  }
412
462
  if (!provider) {
413
- throw new common_1.BadRequestException('Phone or email authentication is not enabled');
463
+ throw new common_1.BadRequestException({
464
+ message: 'Phone or email authentication is not enabled',
465
+ code: auth_constants_1.ERROR_CODES.PROVIDER_NOT_FOUND,
466
+ });
414
467
  }
415
468
  if (!provider.enabled) {
416
469
  if (email) {
417
- throw new common_1.BadRequestException('Email authentication is not enabled');
470
+ throw new common_1.BadRequestException({
471
+ message: 'Email authentication is not enabled',
472
+ code: auth_constants_1.ERROR_CODES.PROVIDER_NOT_FOUND,
473
+ });
418
474
  }
419
475
  else if (phone) {
420
- throw new common_1.BadRequestException('Phone authentication is not enabled');
476
+ throw new common_1.BadRequestException({
477
+ message: 'Phone authentication is not enabled',
478
+ code: auth_constants_1.ERROR_CODES.PROVIDER_NOT_FOUND,
479
+ });
421
480
  }
422
481
  }
423
482
  const identity = await provider.findIdentity(email || phone);
@@ -460,7 +519,10 @@ let AuthService = class AuthService {
460
519
  // Resolve tenant ID - use provided or default
461
520
  tenantId = await this.tenantService.resolveTenantId(tenantId);
462
521
  if (!email && !phone) {
463
- throw new common_1.BadRequestException('Either email or phone must be provided');
522
+ throw new common_1.BadRequestException({
523
+ message: 'Either email or phone must be provided',
524
+ code: auth_constants_1.ERROR_CODES.EMAIL_OR_PHONE_REQUIRED,
525
+ });
464
526
  }
465
527
  let provider = null;
466
528
  if (phone) {
@@ -470,11 +532,17 @@ let AuthService = class AuthService {
470
532
  provider = this.authProviderRegistry.getProvider(auth_constants_1.EMAIL_AUTH_PROVIDER);
471
533
  }
472
534
  if (!provider) {
473
- throw new common_1.BadRequestException('Phone or email authentication is not enabled');
535
+ throw new common_1.BadRequestException({
536
+ message: 'Phone or email authentication is not enabled',
537
+ code: auth_constants_1.ERROR_CODES.PROVIDER_NOT_FOUND,
538
+ });
474
539
  }
475
540
  const identity = await provider.findIdentity(email || phone);
476
541
  if (!identity) {
477
- throw new common_1.BadRequestException('Invalid reset request');
542
+ throw new common_1.BadRequestException({
543
+ message: 'Invalid reset request',
544
+ code: auth_constants_1.ERROR_CODES.PASSWORD_RESET_INVALID_REQUEST,
545
+ });
478
546
  }
479
547
  const validOtp = await this.otpRepository.findOne({
480
548
  where: {
@@ -486,10 +554,16 @@ let AuthService = class AuthService {
486
554
  relations: ['user']
487
555
  });
488
556
  if (!validOtp) {
489
- throw new common_1.BadRequestException('Invalid OTP code');
557
+ throw new common_1.BadRequestException({
558
+ message: 'Invalid OTP code',
559
+ code: auth_constants_1.ERROR_CODES.OTP_INVALID,
560
+ });
490
561
  }
491
562
  if ((0, moment_1.default)(validOtp.expiresAt).isBefore(new Date())) {
492
- throw new common_1.BadRequestException('OTP code expired');
563
+ throw new common_1.BadRequestException({
564
+ message: 'OTP code expired',
565
+ code: auth_constants_1.ERROR_CODES.OTP_EXPIRED,
566
+ });
493
567
  }
494
568
  const user = validOtp.user;
495
569
  // Generate JWT-based password reset token
@@ -521,7 +595,10 @@ let AuthService = class AuthService {
521
595
  // Resolve tenant ID - use provided or default
522
596
  tenantId = await this.tenantService.resolveTenantId(tenantId);
523
597
  if (!email && !phone) {
524
- throw new common_1.BadRequestException('Either email or phone must be provided');
598
+ throw new common_1.BadRequestException({
599
+ message: 'Either email or phone must be provided',
600
+ code: auth_constants_1.ERROR_CODES.EMAIL_OR_PHONE_REQUIRED,
601
+ });
525
602
  }
526
603
  // Find user by email or phone
527
604
  const user = await this.userRepository.findOne({
@@ -531,7 +608,10 @@ let AuthService = class AuthService {
531
608
  ]
532
609
  });
533
610
  if (!user) {
534
- throw new common_1.BadRequestException('Invalid reset request');
611
+ throw new common_1.BadRequestException({
612
+ message: 'Invalid reset request',
613
+ code: auth_constants_1.ERROR_CODES.PASSWORD_RESET_INVALID_REQUEST,
614
+ });
535
615
  }
536
616
  // Find valid OTP
537
617
  const validOtp = await this.otpRepository.findOne({
@@ -544,7 +624,10 @@ let AuthService = class AuthService {
544
624
  }
545
625
  });
546
626
  if (!validOtp) {
547
- throw new common_1.BadRequestException('Invalid or expired OTP');
627
+ throw new common_1.BadRequestException({
628
+ message: 'Invalid or expired OTP',
629
+ code: auth_constants_1.ERROR_CODES.OTP_INVALID,
630
+ });
548
631
  }
549
632
  // Update password
550
633
  await user.setPassword(newPassword);
@@ -576,23 +659,35 @@ let AuthService = class AuthService {
576
659
  decoded = await this.jwtService.verifyPasswordResetToken(token);
577
660
  }
578
661
  catch (error) {
579
- throw new common_1.BadRequestException('Invalid or expired reset token');
662
+ throw new common_1.BadRequestException({
663
+ message: 'Invalid or expired reset token',
664
+ code: auth_constants_1.ERROR_CODES.PASSWORD_RESET_TOKEN_INVALID,
665
+ });
580
666
  }
581
667
  if (decoded.type !== 'password-reset') {
582
- throw new common_1.BadRequestException('Invalid token type');
668
+ throw new common_1.BadRequestException({
669
+ message: 'Invalid token type',
670
+ code: auth_constants_1.ERROR_CODES.PASSWORD_RESET_TOKEN_INVALID,
671
+ });
583
672
  }
584
673
  // Get user
585
674
  const user = await this.userRepository.findOne({
586
675
  where: { id: decoded.userId }
587
676
  });
588
677
  if (!user) {
589
- throw new common_1.BadRequestException('User not found');
678
+ throw new common_1.BadRequestException({
679
+ message: 'User not found',
680
+ code: auth_constants_1.ERROR_CODES.USER_NOT_FOUND,
681
+ });
590
682
  }
591
683
  // Verify password hasn't changed since token was issued
592
684
  // This makes the token single-use in practice
593
685
  const currentPasswordHashPrefix = user.passwordHash ? user.passwordHash.substring(0, 10) : '';
594
686
  if (decoded.passwordHashPrefix !== currentPasswordHashPrefix) {
595
- throw new common_1.BadRequestException('Reset token is no longer valid');
687
+ throw new common_1.BadRequestException({
688
+ message: 'Reset token is no longer valid',
689
+ code: auth_constants_1.ERROR_CODES.PASSWORD_RESET_TOKEN_INVALID,
690
+ });
596
691
  }
597
692
  // Update password
598
693
  await user.setPassword(newPassword);
@@ -630,7 +725,10 @@ let AuthService = class AuthService {
630
725
  async logoutAll(userId, logoutType = 'user', reason) {
631
726
  const session = request_context_1.RequestContext.currentSession();
632
727
  if (!session) {
633
- throw new common_1.UnauthorizedException('Session not found');
728
+ throw new common_1.UnauthorizedException({
729
+ message: 'Session not found',
730
+ code: auth_constants_1.ERROR_CODES.SESSION_NOT_FOUND,
731
+ });
634
732
  }
635
733
  const sessions = await this.sessionManager.getUserSessions(userId);
636
734
  await this.sessionManager.revokeAllUserSessions(userId);
@@ -651,14 +749,23 @@ let AuthService = class AuthService {
651
749
  try {
652
750
  const user = request_context_1.RequestContext.currentUser();
653
751
  if (!user) {
654
- throw new common_1.UnauthorizedException('User not authenticated');
752
+ throw new common_1.UnauthorizedException({
753
+ message: 'User not authenticated',
754
+ code: auth_constants_1.ERROR_CODES.UNAUTHORIZED,
755
+ });
655
756
  }
656
757
  const fullUser = await this.getUserWithRolesAndPermissions(user.id);
657
758
  if (!fullUser.email) {
658
- throw new common_1.BadRequestException('User does not have an email address');
759
+ throw new common_1.BadRequestException({
760
+ message: 'User does not have an email address',
761
+ code: auth_constants_1.ERROR_CODES.NO_EMAIL_ADDRESS,
762
+ });
659
763
  }
660
764
  if (fullUser.emailVerifiedAt) {
661
- throw new common_1.BadRequestException('Email is already verified');
765
+ throw new common_1.BadRequestException({
766
+ message: 'Email is already verified',
767
+ code: auth_constants_1.ERROR_CODES.EMAIL_ALREADY_VERIFIED,
768
+ });
662
769
  }
663
770
  // Generate OTP
664
771
  const otp = (0, otp_1.generateOtp)();
@@ -690,14 +797,23 @@ let AuthService = class AuthService {
690
797
  try {
691
798
  const user = request_context_1.RequestContext.currentUser();
692
799
  if (!user) {
693
- throw new common_1.UnauthorizedException('User not authenticated');
800
+ throw new common_1.UnauthorizedException({
801
+ message: 'User not authenticated',
802
+ code: auth_constants_1.ERROR_CODES.UNAUTHORIZED,
803
+ });
694
804
  }
695
805
  const fullUser = await this.getUserWithRolesAndPermissions(user.id);
696
806
  if (!fullUser.email) {
697
- throw new common_1.BadRequestException('User does not have an email address');
807
+ throw new common_1.BadRequestException({
808
+ message: 'User does not have an email address',
809
+ code: auth_constants_1.ERROR_CODES.NO_EMAIL_ADDRESS,
810
+ });
698
811
  }
699
812
  if (fullUser.emailVerifiedAt) {
700
- throw new common_1.BadRequestException('Email is already verified');
813
+ throw new common_1.BadRequestException({
814
+ message: 'Email is already verified',
815
+ code: auth_constants_1.ERROR_CODES.EMAIL_ALREADY_VERIFIED,
816
+ });
701
817
  }
702
818
  // Find valid OTP
703
819
  const validOtp = await this.otpRepository.findOne({
@@ -709,10 +825,16 @@ let AuthService = class AuthService {
709
825
  }
710
826
  });
711
827
  if (!validOtp) {
712
- throw new common_1.BadRequestException('Invalid verification code');
828
+ throw new common_1.BadRequestException({
829
+ message: 'Invalid verification code',
830
+ code: auth_constants_1.ERROR_CODES.VERIFICATION_CODE_INVALID,
831
+ });
713
832
  }
714
833
  if ((0, moment_1.default)(validOtp.expiresAt).isBefore(new Date())) {
715
- throw new common_1.BadRequestException('Verification code has expired');
834
+ throw new common_1.BadRequestException({
835
+ message: 'Verification code has expired',
836
+ code: auth_constants_1.ERROR_CODES.VERIFICATION_CODE_EXPIRED,
837
+ });
716
838
  }
717
839
  // Mark OTP as used
718
840
  validOtp.used = true;
@@ -734,8 +856,8 @@ let AuthService = class AuthService {
734
856
  throw error;
735
857
  }
736
858
  }
737
- generateTokensPayload(session, otherPayload = {}) {
738
- const payload = {
859
+ async generateTokensPayload(session, otherPayload = {}) {
860
+ let payload = {
739
861
  id: session.userId,
740
862
  sub: session.userId,
741
863
  sessionId: session.id,
@@ -748,10 +870,15 @@ let AuthService = class AuthService {
748
870
  isMfaVerified: session.data?.isMfaVerified,
749
871
  ...otherPayload,
750
872
  };
873
+ // Apply custom token payload hook if configured
874
+ const config = this.authConfigService.getConfig();
875
+ if (config.session?.customizeTokenPayload) {
876
+ payload = await config.session.customizeTokenPayload(payload, session);
877
+ }
751
878
  return payload;
752
879
  }
753
880
  async generateTokensFromSession(session) {
754
- const payload = this.generateTokensPayload(session);
881
+ const payload = await this.generateTokensPayload(session);
755
882
  const tokens = await this.jwtService.generateTokens(payload);
756
883
  return tokens;
757
884
  }
@@ -1 +1 @@
1
- {"version":3,"file":"mfa.service.d.ts","sourceRoot":"","sources":["../../../../../../../packages/nest-auth/src/lib/auth/services/mfa.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"mfa.service.d.ts","sourceRoot":"","sources":["../../../../../../../packages/nest-auth/src/lib/auth/services/mfa.service.ts"],"names":[],"mappings":"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"}
@@ -17,7 +17,6 @@ const otp_1 = require("../../utils/otp");
17
17
  const ms_1 = tslib_1.__importDefault(require("ms"));
18
18
  const auth_config_service_1 = require("../../core/services/auth-config.service");
19
19
  const event_emitter_1 = require("@nestjs/event-emitter");
20
- const auth_constants_2 = require("../../auth.constants");
21
20
  const two_factor_code_sent_event_1 = require("../events/two-factor-code-sent.event");
22
21
  const trusted_device_entity_1 = require("../entities/trusted-device.entity");
23
22
  const crypto_1 = require("crypto");
@@ -33,7 +32,10 @@ let MfaService = class MfaService {
33
32
  requireMfaEnabledForApp(throwError = true) {
34
33
  if (!this.mfaConfig.enabled) {
35
34
  if (throwError) {
36
- throw new common_1.ForbiddenException('MFA is not enabled for the application');
35
+ throw new common_1.ForbiddenException({
36
+ message: 'MFA is not enabled for the application',
37
+ code: auth_constants_1.ERROR_CODES.MFA_NOT_ENABLED,
38
+ });
37
39
  }
38
40
  return false;
39
41
  }
@@ -122,7 +124,7 @@ let MfaService = class MfaService {
122
124
  if (method === mfa_options_interface_1.MFAMethodEnum.EMAIL || method === mfa_options_interface_1.MFAMethodEnum.SMS) {
123
125
  const user = await this.userRepository.findOne({ where: { id: userId } });
124
126
  if (user) {
125
- await this.eventEmitter.emitAsync(auth_constants_2.NestAuthEvents.TWO_FACTOR_CODE_SENT, new two_factor_code_sent_event_1.TwoFactorCodeSentEvent({
127
+ await this.eventEmitter.emitAsync(auth_constants_1.NestAuthEvents.TWO_FACTOR_CODE_SENT, new two_factor_code_sent_event_1.TwoFactorCodeSentEvent({
126
128
  user,
127
129
  tenantId: user.tenantId,
128
130
  method,
@@ -263,18 +265,27 @@ let MfaService = class MfaService {
263
265
  async enableMFA(userId) {
264
266
  this.requireMfaEnabledForApp(true);
265
267
  if (!this.mfaConfig.allowUserToggle) {
266
- throw new Error('MFA toggling is not allowed');
268
+ throw new common_1.ForbiddenException({
269
+ message: 'MFA toggling is not allowed',
270
+ code: auth_constants_1.ERROR_CODES.MFA_TOGGLING_NOT_ALLOWED,
271
+ });
267
272
  }
268
273
  const verifiedMethods = await this.getVerifiedMethods(userId);
269
274
  if (verifiedMethods.length === 0) {
270
- throw new common_1.ForbiddenException('Cannot enable MFA without at least one verified method');
275
+ throw new common_1.ForbiddenException({
276
+ message: 'Cannot enable MFA without at least one verified method',
277
+ code: auth_constants_1.ERROR_CODES.MFA_CANNOT_ENABLE_WITHOUT_METHOD,
278
+ });
271
279
  }
272
280
  await this.userRepository.update(userId, { isMfaEnabled: true });
273
281
  }
274
282
  async disableMFA(userId) {
275
283
  this.checkIsMfaEnabledForApp(true);
276
284
  if (!this.mfaConfig.allowUserToggle) {
277
- throw new Error('MFA toggling is not allowed');
285
+ throw new common_1.ForbiddenException({
286
+ message: 'MFA toggling is not allowed',
287
+ code: auth_constants_1.ERROR_CODES.MFA_TOGGLING_NOT_ALLOWED,
288
+ });
278
289
  }
279
290
  await this.userRepository.update(userId, { isMfaEnabled: false });
280
291
  }
@@ -296,7 +307,7 @@ let MfaService = class MfaService {
296
307
  if (!user) {
297
308
  throw new common_1.UnauthorizedException({
298
309
  message: 'User not found',
299
- code: auth_constants_1.USER_NOT_FOUND_EXCEPTION_CODE
310
+ code: auth_constants_1.ERROR_CODES.USER_NOT_FOUND
300
311
  });
301
312
  }
302
313
  if (user.mfaRecoveryCode === code) {
@@ -310,7 +321,7 @@ let MfaService = class MfaService {
310
321
  }
311
322
  throw new common_1.UnauthorizedException({
312
323
  message: 'Invalid recovery code',
313
- code: auth_constants_1.INVALID_MFA_EXCEPTION_CODE
324
+ code: auth_constants_1.ERROR_CODES.MFA_RECOVERY_CODE_INVALID
314
325
  });
315
326
  }
316
327
  getAvailableMethods() {