@ackplus/nest-auth 1.1.17 → 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 -57
  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,13 +199,13 @@ 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
211
  const trustCookieName = auth_config_service_1.AuthConfigService.getOptions().mfa?.trustDeviceStorageName || auth_constants_1.NEST_AUTH_TRUST_DEVICE_KEY;
@@ -190,12 +220,13 @@ let AuthService = class AuthService {
190
220
  if (isTrusted) {
191
221
  isRequiresMfa = false;
192
222
  // Update session to indicate MFA is verified by trust
193
- await this.sessionManager.updateSession(session.id, {
223
+ session = await this.sessionManager.updateSession(session.id, {
194
224
  data: { ...session.data, isMfaVerified: true }
195
225
  });
196
226
  }
197
227
  }
198
228
  }
229
+ const tokens = await this.generateTokensFromSession(session);
199
230
  // Emit login event
200
231
  await this.eventEmitter.emitAsync(auth_constants_1.NestAuthEvents.LOGGED_IN, new user_logged_in_event_1.UserLoggedInEvent({
201
232
  user,
@@ -206,11 +237,18 @@ let AuthService = class AuthService {
206
237
  tokens,
207
238
  isRequiresMfa
208
239
  }));
209
- return {
240
+ // Build default response
241
+ let response = {
210
242
  accessToken: tokens.accessToken,
211
243
  refreshToken: tokens.refreshToken,
212
244
  isRequiresMfa: isRequiresMfa,
213
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;
214
252
  }
215
253
  async verify2fa(input) {
216
254
  this.debugLogger.logFunctionEntry('verify2fa', 'AuthService', { method: input.method });
@@ -220,7 +258,7 @@ let AuthService = class AuthService {
220
258
  this.debugLogger.error('Session not found for 2FA verification', 'AuthService');
221
259
  throw new common_1.UnauthorizedException({
222
260
  message: 'Session not found',
223
- code: auth_constants_1.SESSION_NOT_FOUND_ERROR,
261
+ code: auth_constants_1.ERROR_CODES.SESSION_NOT_FOUND,
224
262
  });
225
263
  }
226
264
  this.debugLogger.debug('Verifying MFA code', 'AuthService', { userId: session.userId, method: input.method });
@@ -229,7 +267,7 @@ let AuthService = class AuthService {
229
267
  this.debugLogger.warn('Invalid MFA code provided', 'AuthService', { userId: session.userId, method: input.method });
230
268
  throw new common_1.UnauthorizedException({
231
269
  message: 'Invalid MFA code',
232
- code: auth_constants_1.INVALID_MFA_EXCEPTION_CODE,
270
+ code: auth_constants_1.ERROR_CODES.MFA_CODE_INVALID,
233
271
  });
234
272
  }
235
273
  this.debugLogger.debug('Updating session with MFA verification', 'AuthService', { sessionId: session.id });
@@ -272,7 +310,10 @@ let AuthService = class AuthService {
272
310
  async send2faCode(userId, method) {
273
311
  const user = await this.userRepository.findOne({ where: { id: userId } });
274
312
  if (!user) {
275
- 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
+ });
276
317
  }
277
318
  await this.mfaService.sendMfaCode(user.id, method);
278
319
  return true;
@@ -305,7 +346,7 @@ let AuthService = class AuthService {
305
346
  this.debugLogger.error('No refresh token provided', 'AuthService');
306
347
  throw new common_1.UnauthorizedException({
307
348
  message: 'No refresh token provided',
308
- code: auth_constants_1.REFRESH_TOKEN_INVALID,
349
+ code: auth_constants_1.ERROR_CODES.REFRESH_TOKEN_INVALID,
309
350
  });
310
351
  }
311
352
  this.debugLogger.debug('Verifying refresh token', 'AuthService');
@@ -317,20 +358,18 @@ let AuthService = class AuthService {
317
358
  this.debugLogger.warn('Invalid or expired refresh token', 'AuthService');
318
359
  throw new common_1.UnauthorizedException({
319
360
  message: 'Invalid or expired refresh token',
320
- code: auth_constants_1.REFRESH_TOKEN_EXPIRED,
361
+ code: auth_constants_1.ERROR_CODES.REFRESH_TOKEN_EXPIRED,
321
362
  });
322
363
  }
323
364
  const session = await this.sessionManager.getSession(payload.sessionId);
324
365
  if (!session) {
325
366
  throw new common_1.UnauthorizedException({
326
367
  message: 'Invalid refresh token',
327
- code: auth_constants_1.REFRESH_TOKEN_INVALID,
368
+ code: auth_constants_1.ERROR_CODES.REFRESH_TOKEN_INVALID,
328
369
  });
329
370
  }
330
- // Generate new session
331
- const newSession = await this.sessionManager.createSessionFromSession(session);
332
- // Revoke old session
333
- await this.sessionManager.revokeSession(session.id);
371
+ // Refresh existing session
372
+ const newSession = await this.sessionManager.refreshSession(session);
334
373
  // Generate new tokens
335
374
  this.debugLogger.debug('Generating new tokens from refreshed session', 'AuthService', { sessionId: newSession.id });
336
375
  const tokens = await this.generateTokensFromSession(newSession);
@@ -354,20 +393,32 @@ let AuthService = class AuthService {
354
393
  try {
355
394
  const currentUser = request_context_1.RequestContext.currentUser();
356
395
  if (!currentUser?.id) {
357
- 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
+ });
358
400
  }
359
401
  const user = await this.userRepository.findOne({
360
402
  where: { id: currentUser.id },
361
403
  });
362
404
  if (!user) {
363
- 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
+ });
364
409
  }
365
410
  const isValid = await user.validatePassword(input.currentPassword);
366
411
  if (!isValid) {
367
- 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
+ });
368
416
  }
369
417
  if (input.currentPassword === input.newPassword) {
370
- 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
+ });
371
422
  }
372
423
  await user.setPassword(input.newPassword);
373
424
  await this.userRepository.save(user);
@@ -403,17 +454,29 @@ let AuthService = class AuthService {
403
454
  provider = this.authProviderRegistry.getProvider(auth_constants_1.EMAIL_AUTH_PROVIDER);
404
455
  }
405
456
  else {
406
- 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
+ });
407
461
  }
408
462
  if (!provider) {
409
- 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
+ });
410
467
  }
411
468
  if (!provider.enabled) {
412
469
  if (email) {
413
- 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
+ });
414
474
  }
415
475
  else if (phone) {
416
- 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
+ });
417
480
  }
418
481
  }
419
482
  const identity = await provider.findIdentity(email || phone);
@@ -456,7 +519,10 @@ let AuthService = class AuthService {
456
519
  // Resolve tenant ID - use provided or default
457
520
  tenantId = await this.tenantService.resolveTenantId(tenantId);
458
521
  if (!email && !phone) {
459
- 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
+ });
460
526
  }
461
527
  let provider = null;
462
528
  if (phone) {
@@ -466,11 +532,17 @@ let AuthService = class AuthService {
466
532
  provider = this.authProviderRegistry.getProvider(auth_constants_1.EMAIL_AUTH_PROVIDER);
467
533
  }
468
534
  if (!provider) {
469
- 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
+ });
470
539
  }
471
540
  const identity = await provider.findIdentity(email || phone);
472
541
  if (!identity) {
473
- 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
+ });
474
546
  }
475
547
  const validOtp = await this.otpRepository.findOne({
476
548
  where: {
@@ -482,10 +554,16 @@ let AuthService = class AuthService {
482
554
  relations: ['user']
483
555
  });
484
556
  if (!validOtp) {
485
- 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
+ });
486
561
  }
487
562
  if ((0, moment_1.default)(validOtp.expiresAt).isBefore(new Date())) {
488
- 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
+ });
489
567
  }
490
568
  const user = validOtp.user;
491
569
  // Generate JWT-based password reset token
@@ -517,7 +595,10 @@ let AuthService = class AuthService {
517
595
  // Resolve tenant ID - use provided or default
518
596
  tenantId = await this.tenantService.resolveTenantId(tenantId);
519
597
  if (!email && !phone) {
520
- 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
+ });
521
602
  }
522
603
  // Find user by email or phone
523
604
  const user = await this.userRepository.findOne({
@@ -527,7 +608,10 @@ let AuthService = class AuthService {
527
608
  ]
528
609
  });
529
610
  if (!user) {
530
- 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
+ });
531
615
  }
532
616
  // Find valid OTP
533
617
  const validOtp = await this.otpRepository.findOne({
@@ -540,7 +624,10 @@ let AuthService = class AuthService {
540
624
  }
541
625
  });
542
626
  if (!validOtp) {
543
- 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
+ });
544
631
  }
545
632
  // Update password
546
633
  await user.setPassword(newPassword);
@@ -572,23 +659,35 @@ let AuthService = class AuthService {
572
659
  decoded = await this.jwtService.verifyPasswordResetToken(token);
573
660
  }
574
661
  catch (error) {
575
- 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
+ });
576
666
  }
577
667
  if (decoded.type !== 'password-reset') {
578
- 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
+ });
579
672
  }
580
673
  // Get user
581
674
  const user = await this.userRepository.findOne({
582
675
  where: { id: decoded.userId }
583
676
  });
584
677
  if (!user) {
585
- 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
+ });
586
682
  }
587
683
  // Verify password hasn't changed since token was issued
588
684
  // This makes the token single-use in practice
589
685
  const currentPasswordHashPrefix = user.passwordHash ? user.passwordHash.substring(0, 10) : '';
590
686
  if (decoded.passwordHashPrefix !== currentPasswordHashPrefix) {
591
- 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
+ });
592
691
  }
593
692
  // Update password
594
693
  await user.setPassword(newPassword);
@@ -626,7 +725,10 @@ let AuthService = class AuthService {
626
725
  async logoutAll(userId, logoutType = 'user', reason) {
627
726
  const session = request_context_1.RequestContext.currentSession();
628
727
  if (!session) {
629
- 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
+ });
630
732
  }
631
733
  const sessions = await this.sessionManager.getUserSessions(userId);
632
734
  await this.sessionManager.revokeAllUserSessions(userId);
@@ -647,14 +749,23 @@ let AuthService = class AuthService {
647
749
  try {
648
750
  const user = request_context_1.RequestContext.currentUser();
649
751
  if (!user) {
650
- 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
+ });
651
756
  }
652
757
  const fullUser = await this.getUserWithRolesAndPermissions(user.id);
653
758
  if (!fullUser.email) {
654
- 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
+ });
655
763
  }
656
764
  if (fullUser.emailVerifiedAt) {
657
- 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
+ });
658
769
  }
659
770
  // Generate OTP
660
771
  const otp = (0, otp_1.generateOtp)();
@@ -686,14 +797,23 @@ let AuthService = class AuthService {
686
797
  try {
687
798
  const user = request_context_1.RequestContext.currentUser();
688
799
  if (!user) {
689
- 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
+ });
690
804
  }
691
805
  const fullUser = await this.getUserWithRolesAndPermissions(user.id);
692
806
  if (!fullUser.email) {
693
- 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
+ });
694
811
  }
695
812
  if (fullUser.emailVerifiedAt) {
696
- 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
+ });
697
817
  }
698
818
  // Find valid OTP
699
819
  const validOtp = await this.otpRepository.findOne({
@@ -705,10 +825,16 @@ let AuthService = class AuthService {
705
825
  }
706
826
  });
707
827
  if (!validOtp) {
708
- 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
+ });
709
832
  }
710
833
  if ((0, moment_1.default)(validOtp.expiresAt).isBefore(new Date())) {
711
- 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
+ });
712
838
  }
713
839
  // Mark OTP as used
714
840
  validOtp.used = true;
@@ -730,8 +856,8 @@ let AuthService = class AuthService {
730
856
  throw error;
731
857
  }
732
858
  }
733
- generateTokensPayload(session, otherPayload = {}) {
734
- const payload = {
859
+ async generateTokensPayload(session, otherPayload = {}) {
860
+ let payload = {
735
861
  id: session.userId,
736
862
  sub: session.userId,
737
863
  sessionId: session.id,
@@ -744,10 +870,15 @@ let AuthService = class AuthService {
744
870
  isMfaVerified: session.data?.isMfaVerified,
745
871
  ...otherPayload,
746
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
+ }
747
878
  return payload;
748
879
  }
749
880
  async generateTokensFromSession(session) {
750
- const payload = this.generateTokensPayload(session);
881
+ const payload = await this.generateTokensPayload(session);
751
882
  const tokens = await this.jwtService.generateTokens(payload);
752
883
  return tokens;
753
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() {