@nauth-toolkit/core 0.1.35 → 0.1.37
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/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +1 -1
- package/dist/bootstrap.js.map +1 -1
- package/dist/dto/auth-response.dto.d.ts +60 -54
- package/dist/dto/auth-response.dto.d.ts.map +1 -1
- package/dist/dto/auth-response.dto.js +23 -11
- package/dist/dto/auth-response.dto.js.map +1 -1
- package/dist/dto/login.dto.js +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/interfaces/config.interface.d.ts +26 -254
- package/dist/interfaces/config.interface.d.ts.map +1 -1
- package/dist/interfaces/hooks.interface.d.ts +100 -0
- package/dist/interfaces/hooks.interface.d.ts.map +1 -0
- package/dist/interfaces/hooks.interface.js +12 -0
- package/dist/interfaces/hooks.interface.js.map +1 -0
- package/dist/interfaces/index.d.ts +1 -0
- package/dist/interfaces/index.d.ts.map +1 -1
- package/dist/interfaces/index.js +1 -0
- package/dist/interfaces/index.js.map +1 -1
- package/dist/internal.d.ts +5 -0
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +10 -1
- package/dist/internal.js.map +1 -1
- package/dist/schemas/auth-config.schema.d.ts +32 -158
- package/dist/schemas/auth-config.schema.d.ts.map +1 -1
- package/dist/schemas/auth-config.schema.js +1 -15
- package/dist/schemas/auth-config.schema.js.map +1 -1
- package/dist/services/adaptive-mfa-decision.service.d.ts.map +1 -1
- package/dist/services/adaptive-mfa-decision.service.js +4 -34
- package/dist/services/adaptive-mfa-decision.service.js.map +1 -1
- package/dist/services/auth-challenge-helper.service.d.ts.map +1 -1
- package/dist/services/auth-challenge-helper.service.js +2 -11
- package/dist/services/auth-challenge-helper.service.js.map +1 -1
- package/dist/services/auth.service.d.ts +3 -1
- package/dist/services/auth.service.d.ts.map +1 -1
- package/dist/services/auth.service.js +67 -128
- package/dist/services/auth.service.js.map +1 -1
- package/dist/services/hook-registry.service.d.ts +74 -0
- package/dist/services/hook-registry.service.d.ts.map +1 -0
- package/dist/services/hook-registry.service.js +125 -0
- package/dist/services/hook-registry.service.js.map +1 -0
- package/dist/services/social-auth-base.service.d.ts +3 -1
- package/dist/services/social-auth-base.service.d.ts.map +1 -1
- package/dist/services/social-auth-base.service.js +14 -40
- package/dist/services/social-auth-base.service.js.map +1 -1
- package/dist/services/social-redirect.handler.d.ts +1 -1
- package/dist/utils/setup/init-services.d.ts +2 -1
- package/dist/utils/setup/init-services.d.ts.map +1 -1
- package/dist/utils/setup/init-services.js +4 -1
- package/dist/utils/setup/init-services.js.map +1 -1
- package/dist/utils/setup/init-social.d.ts +1 -1
- package/dist/utils/setup/init-social.d.ts.map +1 -1
- package/dist/utils/setup/init-social.js +4 -4
- package/dist/utils/setup/init-social.js.map +1 -1
- package/package.json +1 -1
|
@@ -48,6 +48,7 @@ const login_dto_1 = require("../dto/login.dto");
|
|
|
48
48
|
const change_password_request_dto_1 = require("../dto/change-password-request.dto");
|
|
49
49
|
const update_user_attributes_request_dto_1 = require("../dto/update-user-attributes-request.dto");
|
|
50
50
|
const user_response_dto_1 = require("../dto/user-response.dto");
|
|
51
|
+
const auth_response_dto_1 = require("../dto/auth-response.dto");
|
|
51
52
|
const auth_challenge_dto_1 = require("../dto/auth-challenge.dto");
|
|
52
53
|
const respond_challenge_dto_1 = require("../dto/respond-challenge.dto");
|
|
53
54
|
const get_user_by_email_dto_1 = require("../dto/get-user-by-email.dto");
|
|
@@ -92,6 +93,7 @@ class AuthService {
|
|
|
92
93
|
accountLockoutStorage;
|
|
93
94
|
config;
|
|
94
95
|
logger;
|
|
96
|
+
hookRegistry;
|
|
95
97
|
auditService;
|
|
96
98
|
phoneVerificationService;
|
|
97
99
|
mfaService;
|
|
@@ -105,7 +107,7 @@ class AuthService {
|
|
|
105
107
|
challengeSessionRepository;
|
|
106
108
|
authAuditRepository;
|
|
107
109
|
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)
|
|
110
|
+
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
111
|
phoneVerificationService, // Optional - only available when SMS provider is configured
|
|
110
112
|
mfaService, // Optional - available when MFA modules are imported
|
|
111
113
|
mfaDeviceRepository, // Optional - available when MFA modules are imported
|
|
@@ -130,6 +132,7 @@ class AuthService {
|
|
|
130
132
|
this.accountLockoutStorage = accountLockoutStorage;
|
|
131
133
|
this.config = config;
|
|
132
134
|
this.logger = logger;
|
|
135
|
+
this.hookRegistry = hookRegistry;
|
|
133
136
|
this.auditService = auditService;
|
|
134
137
|
this.phoneVerificationService = phoneVerificationService;
|
|
135
138
|
this.mfaService = mfaService;
|
|
@@ -229,20 +232,7 @@ class AuthService {
|
|
|
229
232
|
// ============================================================================
|
|
230
233
|
// Execute preSignup hook before user creation
|
|
231
234
|
// Hook can throw NAuthException with PRESIGNUP_FAILED to block signup with custom message
|
|
232
|
-
|
|
233
|
-
try {
|
|
234
|
-
await this.config.hooks.preSignup(dto, 'password', undefined, false);
|
|
235
|
-
}
|
|
236
|
-
catch (hookError) {
|
|
237
|
-
// If hook throws NAuthException with PRESIGNUP_FAILED, re-throw it
|
|
238
|
-
if (hookError instanceof nauth_exception_1.NAuthException && hookError.code === error_codes_enum_1.AuthErrorCode.PRESIGNUP_FAILED) {
|
|
239
|
-
throw hookError;
|
|
240
|
-
}
|
|
241
|
-
// For other errors, wrap in PRESIGNUP_FAILED
|
|
242
|
-
const errorMessage = hookError instanceof Error ? hookError.message : 'Pre-signup validation failed';
|
|
243
|
-
throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.PRESIGNUP_FAILED, errorMessage);
|
|
244
|
-
}
|
|
245
|
-
}
|
|
235
|
+
await this.hookRegistry.executePreSignup(dto, 'password', undefined, false);
|
|
246
236
|
// Determine verification requirements based on verification method
|
|
247
237
|
const verificationMethod = this.config.signup?.verificationMethod;
|
|
248
238
|
// Validate required fields based on verification method
|
|
@@ -333,20 +323,23 @@ class AuthService {
|
|
|
333
323
|
// All verification codes are sent when challenges are created (in AuthChallengeHelperService.createChallengeResponse)
|
|
334
324
|
// This ensures proper sequential flow: email code first, then phone code after email is verified
|
|
335
325
|
// This prevents user confusion from receiving multiple codes at once
|
|
336
|
-
//
|
|
337
|
-
//
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
}
|
|
326
|
+
// ============================================================================
|
|
327
|
+
// Lifecycle Hook: postSignup
|
|
328
|
+
// ============================================================================
|
|
329
|
+
// Execute postSignup hook immediately after account creation (non-blocking)
|
|
330
|
+
await this.hookRegistry.executePostSignup(savedUser, {
|
|
331
|
+
requiresVerification: verificationMethod !== 'none',
|
|
332
|
+
signupType: 'password',
|
|
333
|
+
adminSignup: false,
|
|
334
|
+
});
|
|
335
|
+
// ============================================================================
|
|
336
|
+
// refresh user data in case post signup hook has modified the user
|
|
337
|
+
// ============================================================================
|
|
338
|
+
const refreshedUser = await this.userRepository.findOne({
|
|
339
|
+
where: { id: savedUser.id },
|
|
340
|
+
});
|
|
341
|
+
if (refreshedUser) {
|
|
342
|
+
savedUser = refreshedUser;
|
|
350
343
|
}
|
|
351
344
|
// ============================================================================
|
|
352
345
|
// Challenge System: Determine if user needs to complete challenges
|
|
@@ -476,20 +469,7 @@ class AuthService {
|
|
|
476
469
|
// ============================================================================
|
|
477
470
|
// Execute preSignup hook before user creation (admin signup)
|
|
478
471
|
// Hook can throw NAuthException with PRESIGNUP_FAILED to block signup with custom message
|
|
479
|
-
|
|
480
|
-
try {
|
|
481
|
-
await this.config.hooks.preSignup(dto, 'password', undefined, true);
|
|
482
|
-
}
|
|
483
|
-
catch (hookError) {
|
|
484
|
-
// If hook throws NAuthException with PRESIGNUP_FAILED, re-throw it
|
|
485
|
-
if (hookError instanceof nauth_exception_1.NAuthException && hookError.code === error_codes_enum_1.AuthErrorCode.PRESIGNUP_FAILED) {
|
|
486
|
-
throw hookError;
|
|
487
|
-
}
|
|
488
|
-
// For other errors, wrap in PRESIGNUP_FAILED
|
|
489
|
-
const errorMessage = hookError instanceof Error ? hookError.message : 'Pre-signup validation failed';
|
|
490
|
-
throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.PRESIGNUP_FAILED, errorMessage);
|
|
491
|
-
}
|
|
492
|
-
}
|
|
472
|
+
await this.hookRegistry.executePreSignup(dto, 'password', undefined, true);
|
|
493
473
|
// Create user with override flags
|
|
494
474
|
this.logger?.debug?.(`Creating admin user record for: ${dto.email} || ${dto.username} || ${dto.phone} (isEmailVerified: ${dto.isEmailVerified || false}, isPhoneVerified: ${dto.isPhoneVerified || false})`);
|
|
495
475
|
const user = this.userRepository.create({
|
|
@@ -570,6 +550,14 @@ class AuthService {
|
|
|
570
550
|
this.logger?.error?.(`Admin signup failed - database error: ${errorMessage}`);
|
|
571
551
|
throw error;
|
|
572
552
|
}
|
|
553
|
+
// ============================================================================
|
|
554
|
+
// Lifecycle Hook: afterSignup
|
|
555
|
+
// ============================================================================
|
|
556
|
+
// Execute afterSignup hook immediately after account creation (non-blocking)
|
|
557
|
+
await this.hookRegistry.executePostSignup(savedUser, {
|
|
558
|
+
signupType: 'password',
|
|
559
|
+
adminSignup: true,
|
|
560
|
+
});
|
|
573
561
|
// No tokens, no challenge system, no verification emails - pure user creation
|
|
574
562
|
// Return sanitized user object (excludes passwordHash and other sensitive fields)
|
|
575
563
|
const userDto = user_response_dto_1.UserResponseDto.fromEntity(savedUser);
|
|
@@ -702,29 +690,16 @@ class AuthService {
|
|
|
702
690
|
// ============================================================================
|
|
703
691
|
// Execute preSignup hook before user creation (admin social signup)
|
|
704
692
|
// Hook can throw NAuthException with PRESIGNUP_FAILED to block signup with custom message
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
};
|
|
716
|
-
await this.config.hooks.preSignup(profileData, 'social', dto.provider, true);
|
|
717
|
-
}
|
|
718
|
-
catch (hookError) {
|
|
719
|
-
// If hook throws NAuthException with PRESIGNUP_FAILED, re-throw it
|
|
720
|
-
if (hookError instanceof nauth_exception_1.NAuthException && hookError.code === error_codes_enum_1.AuthErrorCode.PRESIGNUP_FAILED) {
|
|
721
|
-
throw hookError;
|
|
722
|
-
}
|
|
723
|
-
// For other errors, wrap in PRESIGNUP_FAILED
|
|
724
|
-
const errorMessage = hookError instanceof Error ? hookError.message : 'Pre-signup validation failed';
|
|
725
|
-
throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.PRESIGNUP_FAILED, errorMessage);
|
|
726
|
-
}
|
|
727
|
-
}
|
|
693
|
+
// Convert AdminSignupSocialDTO to profile-like structure for hook
|
|
694
|
+
const profileData = {
|
|
695
|
+
email: dto.email,
|
|
696
|
+
id: dto.providerId,
|
|
697
|
+
firstName: dto.firstName,
|
|
698
|
+
lastName: dto.lastName,
|
|
699
|
+
verified: true, // Admin signup always has verified email
|
|
700
|
+
raw: dto.socialMetadata,
|
|
701
|
+
};
|
|
702
|
+
await this.hookRegistry.executePreSignup(profileData, 'social', dto.provider, true);
|
|
728
703
|
// Create user with override flags
|
|
729
704
|
// Note: Email is always verified for social imports (like normal social signup)
|
|
730
705
|
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})`);
|
|
@@ -759,23 +734,12 @@ class AuthService {
|
|
|
759
734
|
// ============================================================================
|
|
760
735
|
// Lifecycle Hook: afterSignup
|
|
761
736
|
// ============================================================================
|
|
762
|
-
// Execute afterSignup hook immediately after account creation
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
requiresVerification: !savedUser.isEmailVerified || !savedUser.isPhoneVerified,
|
|
769
|
-
signupType: 'social',
|
|
770
|
-
provider: dto.provider,
|
|
771
|
-
});
|
|
772
|
-
}
|
|
773
|
-
catch (hookError) {
|
|
774
|
-
// Non-blocking: auth succeeded; hook errors should not break signup
|
|
775
|
-
const errorMessage = hookError instanceof Error ? hookError.message : 'Unknown error';
|
|
776
|
-
this.logger?.error?.(`afterSignup hook failed (continuing): ${errorMessage}`, { error: hookError });
|
|
777
|
-
}
|
|
778
|
-
}
|
|
737
|
+
// Execute afterSignup hook immediately after account creation (non-blocking)
|
|
738
|
+
await this.hookRegistry.executePostSignup(savedUser, {
|
|
739
|
+
signupType: 'social',
|
|
740
|
+
provider: dto.provider,
|
|
741
|
+
adminSignup: true,
|
|
742
|
+
});
|
|
779
743
|
// ============================================================================
|
|
780
744
|
// Audit: Record account creation by admin (social import)
|
|
781
745
|
// ============================================================================
|
|
@@ -1965,18 +1929,10 @@ class AuthService {
|
|
|
1965
1929
|
}
|
|
1966
1930
|
}
|
|
1967
1931
|
// ============================================================================
|
|
1968
|
-
// Lifecycle Hook: afterLogin
|
|
1932
|
+
// Lifecycle Hook: afterLogin (TODO: Implement provider-based hook)
|
|
1969
1933
|
// ============================================================================
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
await this.config.hooks.afterLogin(user, session);
|
|
1973
|
-
}
|
|
1974
|
-
catch (hookError) {
|
|
1975
|
-
const errorMessage = hookError instanceof Error ? hookError.message : 'Unknown error';
|
|
1976
|
-
// Non-blocking: auth succeeded; hook errors should not break login
|
|
1977
|
-
this.logger?.error?.(`afterLogin hook failed (continuing): ${errorMessage}`, { error: hookError });
|
|
1978
|
-
}
|
|
1979
|
-
}
|
|
1934
|
+
// TODO: Implement provider-based hook for afterLogin
|
|
1935
|
+
// await this.hookRegistry.executeAfterLogin(user, session);
|
|
1980
1936
|
// ============================================================================
|
|
1981
1937
|
// Trusted Device Token Management (Remember Device Feature)
|
|
1982
1938
|
// ============================================================================
|
|
@@ -2015,19 +1971,8 @@ class AuthService {
|
|
|
2015
1971
|
// Note: deviceToken inclusion in response body is handled by CookieTokenInterceptor
|
|
2016
1972
|
// which checks route-level @TokenDelivery decorator and global config
|
|
2017
1973
|
// to decide whether to set as cookie and/or strip from body
|
|
2018
|
-
const userDto = user_response_dto_1.UserResponseDto.fromEntity(user);
|
|
2019
1974
|
const authResponse = {
|
|
2020
|
-
user:
|
|
2021
|
-
sub: userDto.sub,
|
|
2022
|
-
email: userDto.email,
|
|
2023
|
-
firstName: userDto.firstName,
|
|
2024
|
-
lastName: userDto.lastName,
|
|
2025
|
-
phone: userDto.phone ?? undefined,
|
|
2026
|
-
isEmailVerified: userDto.isEmailVerified,
|
|
2027
|
-
isPhoneVerified: userDto.isPhoneVerified ?? undefined,
|
|
2028
|
-
socialProviders: userDto.socialProviders && userDto.socialProviders.length > 0 ? userDto.socialProviders : undefined,
|
|
2029
|
-
hasPasswordHash: userDto.hasPasswordHash,
|
|
2030
|
-
},
|
|
1975
|
+
user: (0, auth_response_dto_1.toAuthResponseUser)(user),
|
|
2031
1976
|
accessToken: tokens.accessToken,
|
|
2032
1977
|
refreshToken: tokens.refreshToken,
|
|
2033
1978
|
accessTokenExpiresAt: accessTokenValidation.payload?.exp || 0,
|
|
@@ -3618,22 +3563,24 @@ class AuthService {
|
|
|
3618
3563
|
if (!user || !user.passwordHash) {
|
|
3619
3564
|
throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.NOT_FOUND, 'User not found');
|
|
3620
3565
|
}
|
|
3621
|
-
//
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
|
|
3566
|
+
// ============================================================================
|
|
3567
|
+
// Lifecycle Hook: beforePasswordChange (TODO: Implement provider-based hook)
|
|
3568
|
+
// ============================================================================
|
|
3569
|
+
// TODO: Implement provider-based hook for beforePasswordChange
|
|
3570
|
+
// const allowed = await this.hookRegistry.executeBeforePasswordChange(dto.sub, dto.oldPassword);
|
|
3571
|
+
// if (!allowed) {
|
|
3572
|
+
// throw new NAuthException(AuthErrorCode.PASSWORD_CHANGE_NOT_ALLOWED, 'Password change not allowed');
|
|
3573
|
+
// }
|
|
3628
3574
|
// Verify old password
|
|
3629
3575
|
const isValid = await this.passwordService.verifyPassword(dto.oldPassword, user.passwordHash);
|
|
3630
3576
|
if (!isValid) {
|
|
3631
3577
|
throw new nauth_exception_1.NAuthException(error_codes_enum_1.AuthErrorCode.PASSWORD_INCORRECT, 'Current password is incorrect');
|
|
3632
3578
|
}
|
|
3633
|
-
//
|
|
3634
|
-
|
|
3635
|
-
|
|
3636
|
-
|
|
3579
|
+
// ============================================================================
|
|
3580
|
+
// Lifecycle Hook: afterPasswordChange (TODO: Implement provider-based hook)
|
|
3581
|
+
// ============================================================================
|
|
3582
|
+
// TODO: Implement provider-based hook for afterPasswordChange
|
|
3583
|
+
// await this.hookRegistry.executeAfterPasswordChange(dto.sub);
|
|
3637
3584
|
await this.updateUserPassword({
|
|
3638
3585
|
user,
|
|
3639
3586
|
newPassword: dto.newPassword,
|
|
@@ -4221,18 +4168,10 @@ class AuthService {
|
|
|
4221
4168
|
}
|
|
4222
4169
|
}
|
|
4223
4170
|
// ============================================================================
|
|
4224
|
-
// Lifecycle Hook: afterLoginFailed
|
|
4171
|
+
// Lifecycle Hook: afterLoginFailed (TODO: Implement provider-based hook)
|
|
4225
4172
|
// ============================================================================
|
|
4226
|
-
|
|
4227
|
-
|
|
4228
|
-
await this.config.hooks.afterLoginFailed(identifier, reason || 'unknown');
|
|
4229
|
-
}
|
|
4230
|
-
catch (hookError) {
|
|
4231
|
-
const errorMessage = hookError instanceof Error ? hookError.message : 'Unknown error';
|
|
4232
|
-
// Non-blocking: login already failed; do not throw
|
|
4233
|
-
this.logger?.error?.(`afterLoginFailed hook failed (continuing): ${errorMessage}`, { error: hookError });
|
|
4234
|
-
}
|
|
4235
|
-
}
|
|
4173
|
+
// TODO: Implement provider-based hook for afterLoginFailed
|
|
4174
|
+
// await this.hookRegistry.executeAfterLoginFailed(identifier, reason || 'unknown');
|
|
4236
4175
|
}
|
|
4237
4176
|
/**
|
|
4238
4177
|
* Records a login attempt with client context.
|