@nauth-toolkit/core 0.1.34 → 0.1.36

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 (58) hide show
  1. package/dist/bootstrap.d.ts.map +1 -1
  2. package/dist/bootstrap.js +1 -1
  3. package/dist/bootstrap.js.map +1 -1
  4. package/dist/dto/login.dto.js +1 -1
  5. package/dist/enums/error-codes.enum.d.ts +7 -0
  6. package/dist/enums/error-codes.enum.d.ts.map +1 -1
  7. package/dist/enums/error-codes.enum.js +7 -0
  8. package/dist/enums/error-codes.enum.js.map +1 -1
  9. package/dist/index.d.ts +5 -0
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +7 -1
  12. package/dist/index.js.map +1 -1
  13. package/dist/interfaces/config.interface.d.ts +3 -146
  14. package/dist/interfaces/config.interface.d.ts.map +1 -1
  15. package/dist/interfaces/hooks.interface.d.ts +194 -0
  16. package/dist/interfaces/hooks.interface.d.ts.map +1 -0
  17. package/dist/interfaces/hooks.interface.js +12 -0
  18. package/dist/interfaces/hooks.interface.js.map +1 -0
  19. package/dist/interfaces/index.d.ts +1 -0
  20. package/dist/interfaces/index.d.ts.map +1 -1
  21. package/dist/interfaces/index.js +1 -0
  22. package/dist/interfaces/index.js.map +1 -1
  23. package/dist/internal.d.ts +5 -0
  24. package/dist/internal.d.ts.map +1 -1
  25. package/dist/internal.js +10 -1
  26. package/dist/internal.js.map +1 -1
  27. package/dist/schemas/auth-config.schema.d.ts +0 -126
  28. package/dist/schemas/auth-config.schema.d.ts.map +1 -1
  29. package/dist/schemas/auth-config.schema.js +1 -15
  30. package/dist/schemas/auth-config.schema.js.map +1 -1
  31. package/dist/services/adaptive-mfa-decision.service.d.ts.map +1 -1
  32. package/dist/services/adaptive-mfa-decision.service.js +2 -32
  33. package/dist/services/adaptive-mfa-decision.service.js.map +1 -1
  34. package/dist/services/auth.service.d.ts +3 -1
  35. package/dist/services/auth.service.d.ts.map +1 -1
  36. package/dist/services/auth.service.js +75 -38
  37. package/dist/services/auth.service.js.map +1 -1
  38. package/dist/services/hook-registry.service.d.ts +125 -0
  39. package/dist/services/hook-registry.service.d.ts.map +1 -0
  40. package/dist/services/hook-registry.service.js +177 -0
  41. package/dist/services/hook-registry.service.js.map +1 -0
  42. package/dist/services/social-auth-base.service.d.ts +3 -1
  43. package/dist/services/social-auth-base.service.d.ts.map +1 -1
  44. package/dist/services/social-auth-base.service.js +24 -1
  45. package/dist/services/social-auth-base.service.js.map +1 -1
  46. package/dist/services/social-redirect.handler.d.ts +12 -1
  47. package/dist/services/social-redirect.handler.d.ts.map +1 -1
  48. package/dist/services/social-redirect.handler.js +26 -1
  49. package/dist/services/social-redirect.handler.js.map +1 -1
  50. package/dist/utils/setup/init-services.d.ts +2 -1
  51. package/dist/utils/setup/init-services.d.ts.map +1 -1
  52. package/dist/utils/setup/init-services.js +4 -1
  53. package/dist/utils/setup/init-services.js.map +1 -1
  54. package/dist/utils/setup/init-social.d.ts +1 -1
  55. package/dist/utils/setup/init-social.d.ts.map +1 -1
  56. package/dist/utils/setup/init-social.js +4 -4
  57. package/dist/utils/setup/init-social.js.map +1 -1
  58. package/package.json +1 -1
@@ -92,6 +92,7 @@ class AuthService {
92
92
  accountLockoutStorage;
93
93
  config;
94
94
  logger;
95
+ hookRegistry;
95
96
  auditService;
96
97
  phoneVerificationService;
97
98
  mfaService;
@@ -105,7 +106,7 @@ class AuthService {
105
106
  challengeSessionRepository;
106
107
  authAuditRepository;
107
108
  trustedDeviceRepository;
108
- constructor(userRepository, loginAttemptRepository, passwordService, jwtService, sessionService, challengeService, challengeHelper, emailVerificationService, clientInfoService, accountLockoutStorage, config, logger, auditService, // Optional - audit trail service (enabled via config.auditLogs.enabled)
109
+ constructor(userRepository, loginAttemptRepository, passwordService, jwtService, sessionService, challengeService, challengeHelper, emailVerificationService, clientInfoService, accountLockoutStorage, config, logger, hookRegistry, auditService, // Optional - audit trail service (enabled via config.auditLogs.enabled)
109
110
  phoneVerificationService, // Optional - only available when SMS provider is configured
110
111
  mfaService, // Optional - available when MFA modules are imported
111
112
  mfaDeviceRepository, // Optional - available when MFA modules are imported
@@ -130,6 +131,7 @@ class AuthService {
130
131
  this.accountLockoutStorage = accountLockoutStorage;
131
132
  this.config = config;
132
133
  this.logger = logger;
134
+ this.hookRegistry = hookRegistry;
133
135
  this.auditService = auditService;
134
136
  this.phoneVerificationService = phoneVerificationService;
135
137
  this.mfaService = mfaService;
@@ -224,6 +226,12 @@ class AuthService {
224
226
  }
225
227
  // Hash password
226
228
  const passwordHash = await this.passwordService.hashPassword(dto.password);
229
+ // ============================================================================
230
+ // Lifecycle Hook: preSignup
231
+ // ============================================================================
232
+ // Execute preSignup hook before user creation
233
+ // Hook can throw NAuthException with PRESIGNUP_FAILED to block signup with custom message
234
+ await this.hookRegistry.executePreSignup(dto, 'password', undefined, false);
227
235
  // Determine verification requirements based on verification method
228
236
  const verificationMethod = this.config.signup?.verificationMethod;
229
237
  // Validate required fields based on verification method
@@ -314,10 +322,15 @@ class AuthService {
314
322
  // All verification codes are sent when challenges are created (in AuthChallengeHelperService.createChallengeResponse)
315
323
  // This ensures proper sequential flow: email code first, then phone code after email is verified
316
324
  // This prevents user confusion from receiving multiple codes at once
317
- // Execute afterSignup hook if configured
318
- if (this.config.hooks?.afterSignup) {
319
- await this.config.hooks.afterSignup(savedUser, { requiresVerification: verificationMethod !== 'none' });
320
- }
325
+ // ============================================================================
326
+ // Lifecycle Hook: afterSignup
327
+ // ============================================================================
328
+ // Execute afterSignup hook immediately after account creation (non-blocking)
329
+ await this.hookRegistry.executeAfterSignup(savedUser, {
330
+ requiresVerification: verificationMethod !== 'none',
331
+ signupType: 'password',
332
+ adminSignup: false,
333
+ });
321
334
  // ============================================================================
322
335
  // Challenge System: Determine if user needs to complete challenges
323
336
  // ============================================================================
@@ -441,6 +454,12 @@ class AuthService {
441
454
  // Hash password
442
455
  passwordHash = await this.passwordService.hashPassword(dto.password);
443
456
  }
457
+ // ============================================================================
458
+ // Lifecycle Hook: preSignup
459
+ // ============================================================================
460
+ // Execute preSignup hook before user creation (admin signup)
461
+ // Hook can throw NAuthException with PRESIGNUP_FAILED to block signup with custom message
462
+ await this.hookRegistry.executePreSignup(dto, 'password', undefined, true);
444
463
  // Create user with override flags
445
464
  this.logger?.debug?.(`Creating admin user record for: ${dto.email} || ${dto.username} || ${dto.phone} (isEmailVerified: ${dto.isEmailVerified || false}, isPhoneVerified: ${dto.isPhoneVerified || false})`);
446
465
  const user = this.userRepository.create({
@@ -521,6 +540,14 @@ class AuthService {
521
540
  this.logger?.error?.(`Admin signup failed - database error: ${errorMessage}`);
522
541
  throw error;
523
542
  }
543
+ // ============================================================================
544
+ // Lifecycle Hook: afterSignup
545
+ // ============================================================================
546
+ // Execute afterSignup hook immediately after account creation (non-blocking)
547
+ await this.hookRegistry.executeAfterSignup(savedUser, {
548
+ signupType: 'password',
549
+ adminSignup: true,
550
+ });
524
551
  // No tokens, no challenge system, no verification emails - pure user creation
525
552
  // Return sanitized user object (excludes passwordHash and other sensitive fields)
526
553
  const userDto = user_response_dto_1.UserResponseDto.fromEntity(savedUser);
@@ -648,6 +675,21 @@ class AuthService {
648
675
  // Social-only user: no password (NULL in database)
649
676
  passwordHash = null;
650
677
  }
678
+ // ============================================================================
679
+ // Lifecycle Hook: preSignup
680
+ // ============================================================================
681
+ // Execute preSignup hook before user creation (admin social signup)
682
+ // Hook can throw NAuthException with PRESIGNUP_FAILED to block signup with custom message
683
+ // Convert AdminSignupSocialDTO to profile-like structure for hook
684
+ const profileData = {
685
+ email: dto.email,
686
+ id: dto.providerId,
687
+ firstName: dto.firstName,
688
+ lastName: dto.lastName,
689
+ verified: true, // Admin signup always has verified email
690
+ raw: dto.socialMetadata,
691
+ };
692
+ await this.hookRegistry.executePreSignup(profileData, 'social', dto.provider, true);
651
693
  // Create user with override flags
652
694
  // Note: Email is always verified for social imports (like normal social signup)
653
695
  this.logger?.debug?.(`Creating admin social user record for: ${dto.email} || ${dto.username} || ${dto.phone} (isEmailVerified: true [auto-verified for social], isPhoneVerified: ${dto.isPhoneVerified || false})`);
@@ -680,6 +722,15 @@ class AuthService {
680
722
  savedUser.hasSocialAuth = true;
681
723
  savedUser.socialProviders = [dto.provider];
682
724
  // ============================================================================
725
+ // Lifecycle Hook: afterSignup
726
+ // ============================================================================
727
+ // Execute afterSignup hook immediately after account creation (non-blocking)
728
+ await this.hookRegistry.executeAfterSignup(savedUser, {
729
+ signupType: 'social',
730
+ provider: dto.provider,
731
+ adminSignup: true,
732
+ });
733
+ // ============================================================================
683
734
  // Audit: Record account creation by admin (social import)
684
735
  // ============================================================================
685
736
  try {
@@ -1868,18 +1919,10 @@ class AuthService {
1868
1919
  }
1869
1920
  }
1870
1921
  // ============================================================================
1871
- // Lifecycle Hook: afterLogin
1922
+ // Lifecycle Hook: afterLogin (TODO: Implement provider-based hook)
1872
1923
  // ============================================================================
1873
- if (this.config.hooks?.afterLogin) {
1874
- try {
1875
- await this.config.hooks.afterLogin(user, session);
1876
- }
1877
- catch (hookError) {
1878
- const errorMessage = hookError instanceof Error ? hookError.message : 'Unknown error';
1879
- // Non-blocking: auth succeeded; hook errors should not break login
1880
- this.logger?.error?.(`afterLogin hook failed (continuing): ${errorMessage}`, { error: hookError });
1881
- }
1882
- }
1924
+ // TODO: Implement provider-based hook for afterLogin
1925
+ // await this.hookRegistry.executeAfterLogin(user, session);
1883
1926
  // ============================================================================
1884
1927
  // Trusted Device Token Management (Remember Device Feature)
1885
1928
  // ============================================================================
@@ -3521,22 +3564,24 @@ class AuthService {
3521
3564
  if (!user || !user.passwordHash) {
3522
3565
  throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.NOT_FOUND, 'User not found');
3523
3566
  }
3524
- // Execute beforePasswordChange hook (use sub for external API)
3525
- if (this.config.hooks?.beforePasswordChange) {
3526
- const result = await this.config.hooks.beforePasswordChange(dto.sub, dto.oldPassword);
3527
- if (result === false) {
3528
- throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.PASSWORD_CHANGE_NOT_ALLOWED, 'Password change not allowed');
3529
- }
3530
- }
3567
+ // ============================================================================
3568
+ // Lifecycle Hook: beforePasswordChange (TODO: Implement provider-based hook)
3569
+ // ============================================================================
3570
+ // TODO: Implement provider-based hook for beforePasswordChange
3571
+ // const allowed = await this.hookRegistry.executeBeforePasswordChange(dto.sub, dto.oldPassword);
3572
+ // if (!allowed) {
3573
+ // throw new NAuthException(AuthErrorCode.PASSWORD_CHANGE_NOT_ALLOWED, 'Password change not allowed');
3574
+ // }
3531
3575
  // Verify old password
3532
3576
  const isValid = await this.passwordService.verifyPassword(dto.oldPassword, user.passwordHash);
3533
3577
  if (!isValid) {
3534
3578
  throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.PASSWORD_INCORRECT, 'Current password is incorrect');
3535
3579
  }
3536
- // Execute afterPasswordChange hook (use sub for external API)
3537
- if (this.config.hooks?.afterPasswordChange) {
3538
- await this.config.hooks.afterPasswordChange(dto.sub);
3539
- }
3580
+ // ============================================================================
3581
+ // Lifecycle Hook: afterPasswordChange (TODO: Implement provider-based hook)
3582
+ // ============================================================================
3583
+ // TODO: Implement provider-based hook for afterPasswordChange
3584
+ // await this.hookRegistry.executeAfterPasswordChange(dto.sub);
3540
3585
  await this.updateUserPassword({
3541
3586
  user,
3542
3587
  newPassword: dto.newPassword,
@@ -4124,18 +4169,10 @@ class AuthService {
4124
4169
  }
4125
4170
  }
4126
4171
  // ============================================================================
4127
- // Lifecycle Hook: afterLoginFailed
4172
+ // Lifecycle Hook: afterLoginFailed (TODO: Implement provider-based hook)
4128
4173
  // ============================================================================
4129
- if (this.config.hooks?.afterLoginFailed) {
4130
- try {
4131
- await this.config.hooks.afterLoginFailed(identifier, reason || 'unknown');
4132
- }
4133
- catch (hookError) {
4134
- const errorMessage = hookError instanceof Error ? hookError.message : 'Unknown error';
4135
- // Non-blocking: login already failed; do not throw
4136
- this.logger?.error?.(`afterLoginFailed hook failed (continuing): ${errorMessage}`, { error: hookError });
4137
- }
4138
- }
4174
+ // TODO: Implement provider-based hook for afterLoginFailed
4175
+ // await this.hookRegistry.executeAfterLoginFailed(identifier, reason || 'unknown');
4139
4176
  }
4140
4177
  /**
4141
4178
  * Records a login attempt with client context.