Skip to main content

HookRegistryService

Package: @nauth-toolkit/core/internal Type: Service (Internal)

Central registry for managing authentication lifecycle hooks. Handles hook registration and execution with proper error handling and logging.

import { HookRegistryService } from '@nauth-toolkit/nestjs';

Overview

Provides centralized hook management for authentication lifecycle events. Hooks are executed in registration order.

note

Auto-injected by framework adapters. Manual instantiation not recommended.

Methods

executeAccountLocked()

Internal method. Executes all registered account locked hooks. Called automatically by AuthServiceInternalHelpers. Errors are logged but don't block lockout.

async executeAccountLocked(metadata: AccountLockedMetadata): Promise<void>

executeAccountStatusChanged()

Internal method. Executes all registered account status changed hooks. Called automatically by UserService. Errors are logged but don't block the operation.

async executeAccountStatusChanged(metadata: AccountStatusChangedMetadata): Promise<void>

executeAdaptiveMFARiskDetected()

Internal method. Executes all registered adaptive MFA risk detected hooks. Called automatically by AdaptiveMFADecisionService. Errors are logged but don't block authentication.

async executeAdaptiveMFARiskDetected(metadata: AdaptiveMFARiskDetectedMetadata): Promise<void>

executeEmailChanged()

Internal method. Executes all registered email changed hooks. Called automatically by UserService. Errors are logged but don't block the operation.

async executeEmailChanged(metadata: EmailChangedMetadata): Promise<void>

executeMFADeviceRemoved()

Internal method. Executes all registered MFA device removed hooks. Called automatically by UserService and MFAService. Errors are logged but don't block the operation.

async executeMFADeviceRemoved(metadata: MFADeviceRemovedMetadata): Promise<void>

executeMFAFirstEnabled()

Internal method. Executes all registered MFA first enabled hooks. Called automatically by BaseMFAProviderService. Errors are logged but don't block MFA enrollment.

async executeMFAFirstEnabled(metadata: MFAFirstEnabledMetadata): Promise<void>

executeMFAMethodAdded()

Internal method. Executes all registered MFA method added hooks. Called automatically by BaseMFAProviderService. Errors are logged but don't block MFA enrollment.

async executeMFAMethodAdded(metadata: MFAMethodAddedMetadata): Promise<void>

executeOnboardingCompleted()

Internal method. Executes all registered onboarding completed hooks. Called automatically by AuthService, EmailVerificationService, and PhoneVerificationService. Errors are logged but don't block the flow.

async executeOnboardingCompleted(user: IUser, metadata: OnboardingCompletedMetadata): Promise<void>

Parameters

  • user - User entity
  • metadata - Completion metadata (verification method, source, timestamp)

executePasswordChanged()

Internal method. Executes all registered password changed hooks. Called automatically by AuthServiceInternalHelpers. Errors are logged but don't block the operation.

async executePasswordChanged(metadata: PasswordChangedMetadata): Promise<void>

executePostSignup()

Internal method. Executes all registered post-signup hooks in order. Called automatically by AuthService. Errors are logged but don't block signup.

async executePostSignup(user: IUser, metadata?: SignupMetadata): Promise<void>

Parameters

  • user - Created user entity
  • metadata - Optional signup metadata

executePreSignup()

Internal method. Executes all registered pre-signup hooks in order. Called automatically by AuthService.

async executePreSignup(
data: PreSignupHookData,
signupType: 'password' | 'social',
provider?: string,
adminSignup?: boolean,
): Promise<void>

Parameters

  • data - SignupDTO, AdminSignupDTO, or OAuthUserProfile depending on signup type
  • signupType - Type of signup ('password' or 'social')
  • provider - Social provider name (e.g., 'google', 'apple', 'facebook') - only for social signups
  • adminSignup - Whether this is an admin-initiated signup

Errors

CodeWhenDetails
PRESIGNUP_FAILEDHook throws exception{ message: string }

Throws NAuthException with code PRESIGNUP_FAILED if any hook throws an error.


executeSessionsRevoked()

Internal method. Executes all registered sessions revoked hooks. Called automatically by SessionService. Errors are logged but don't block the operation.

async executeSessionsRevoked(metadata: SessionsRevokedMetadata): Promise<void>

executeUserProfileUpdated()

Internal method. Executes all registered user profile updated hooks in order. Called automatically by AuthService, EmailVerificationService, and PhoneVerificationService. Errors are logged but don't block updates.

async executeUserProfileUpdated(metadata: UserProfileUpdatedMetadata): Promise<void>

Parameters


registerAccountLocked()

Register an account locked hook. Hooks execute when an account is locked due to failed login attempts. Non-blocking - errors are logged.

registerAccountLocked(provider: IAccountLockedHook): void

Parameters

  • provider - IAccountLockedHook

Example

@Injectable()
@AccountLockedHook()
export class LockoutNotificationHook implements IAccountLockedHook {
async execute(metadata) {
await this.alertService.notifyAdmin('account_locked', { userId: metadata.user.sub });
}
}

registerAccountStatusChanged()

Register an account status changed hook. Hooks execute when an account is enabled or disabled by an admin. Non-blocking - errors are logged.

registerAccountStatusChanged(provider: IAccountStatusChangedHook): void

Parameters

  • provider - IAccountStatusChangedHook

Example

@Injectable()
@AccountStatusChangedHook()
export class AccountStatusHook implements IAccountStatusChangedHook {
async execute(metadata) {
await this.auditService.log('account_status_changed', {
userId: metadata.user.sub,
status: metadata.newStatus,
});
}
}

registerAdaptiveMFARiskDetected()

Register an adaptive MFA risk detected hook. Hooks execute when a risk factor is detected during authentication. Non-blocking - errors are logged.

registerAdaptiveMFARiskDetected(provider: IAdaptiveMFARiskDetectedHook): void

Parameters

  • provider - IAdaptiveMFARiskDetectedHook

Example

@Injectable()
@AdaptiveMFARiskDetectedHook()
export class RiskLoggingHook implements IAdaptiveMFARiskDetectedHook {
async execute(metadata) {
await this.securityService.logRiskEvent(metadata.user.sub, metadata.riskFactors);
}
}

registerEmailChanged()

Register an email changed hook. Hooks execute after a user's email address is changed. Non-blocking - errors are logged.

registerEmailChanged(provider: IEmailChangedHook): void

Parameters

  • provider - IEmailChangedHook

Example

@Injectable()
@EmailChangedHook()
export class EmailChangedHook implements IEmailChangedHook {
async execute(metadata) {
await this.crmService.updateEmail(metadata.user.sub, metadata.newEmail);
}
}

registerMFADeviceRemoved()

Register an MFA device removed hook. Hooks execute after an MFA device is removed from a user account. Non-blocking - errors are logged.

registerMFADeviceRemoved(provider: IMFADeviceRemovedHook): void

Parameters

  • provider - IMFADeviceRemovedHook

Example

@Injectable()
@MFADeviceRemovedHook()
export class SecurityAlertHook implements IMFADeviceRemovedHook {
async execute(metadata) {
await this.notifyService.sendSecurityAlert(metadata.user.email, 'mfa_device_removed');
}
}

registerMFAFirstEnabled()

Register an MFA first enabled hook. Hooks execute when a user enables MFA for the first time on their account. Non-blocking - errors are logged.

registerMFAFirstEnabled(provider: IMFAFirstEnabledHook): void

Parameters

  • provider - IMFAFirstEnabledHook

Example

@Injectable()
@MFAFirstEnabledHook()
export class MFAEnrollmentHook implements IMFAFirstEnabledHook {
async execute(metadata) {
await this.analyticsService.track('mfa_first_enabled', { userId: metadata.user.sub });
}
}

registerMFAMethodAdded()

Register an MFA method added hook. Hooks execute when an additional MFA method is added to an account that already has MFA enabled. Non-blocking - errors are logged.

registerMFAMethodAdded(provider: IMFAMethodAddedHook): void

Parameters

  • provider - IMFAMethodAddedHook

Example

@Injectable()
@MFAMethodAddedHook()
export class MFAMethodHook implements IMFAMethodAddedHook {
async execute(metadata) {
await this.analyticsService.track('mfa_method_added', {
userId: metadata.user.sub,
method: metadata.method,
});
}
}

registerOnboardingCompleted()

Register an onboarding completed hook. Hooks execute when a user completes onboarding (email/phone verification). Non-blocking - errors are logged.

registerOnboardingCompleted(provider: IOnboardingCompletedHook): void

Parameters

  • provider - IOnboardingCompletedHook

Example

@Injectable()
@OnboardingCompletedHook()
export class OnboardingHook implements IOnboardingCompletedHook {
async execute(user, metadata) {
await this.analyticsService.track('onboarding_completed', {
userId: user.sub,
method: metadata.verificationMethod,
});
}
}

registerPasswordChanged()

Register a password changed hook. Hooks execute after a user's password is changed. Non-blocking - errors are logged.

registerPasswordChanged(provider: IPasswordChangedHook): void

Parameters

  • provider - IPasswordChangedHook

Example

@Injectable()
@PasswordChangedHook()
export class PasswordAuditHook implements IPasswordChangedHook {
async execute(metadata) {
await this.auditService.log('password_changed', { userId: metadata.user.sub });
}
}

registerPostSignup()

Register a post-signup hook provider. Hooks execute after successful user creation. Non-blocking - errors are logged.

registerPostSignup(provider: IPostSignupHookProvider): void

Parameters

Example

// Use decorators - automatic registration
@Injectable()
@PostSignupHook()
export class WelcomeEmailHook implements IPostSignupHookProvider {
constructor(private emailService: EmailService) {}

async execute(user, metadata) {
// For social signups, include profile picture
if (metadata?.signupType === 'social' && metadata.profilePicture) {
await this.emailService.sendWelcome({
email: user.email,
profilePicture: metadata.profilePicture,
});
} else {
await this.emailService.sendWelcome(user.email);
}
}
}

registerPreSignup()

Register a pre-signup hook provider. Hooks execute before user creation and can block signups.

registerPreSignup(provider: IPreSignupHookProvider): void

Parameters

Example

import { Injectable } from '@nestjs/common';
import { PreSignupHook, IPreSignupHookProvider, PreSignupHookData } from '@nauth-toolkit/nestjs';

// Use decorators - automatic registration
@Injectable()
@PreSignupHook()
export class MyHook implements IPreSignupHookProvider {
async execute(
data: PreSignupHookData,
signupType: 'password' | 'social',
provider?: string,
adminSignup?: boolean,
): Promise<void> {
// Validation logic
}
}

registerSessionsRevoked()

Register a sessions revoked hook. Hooks execute when user sessions are revoked (logout, global sign-out, admin action). Non-blocking - errors are logged.

registerSessionsRevoked(provider: ISessionsRevokedHook): void

Parameters

  • provider - ISessionsRevokedHook

Example

@Injectable()
@SessionsRevokedHook()
export class SessionAuditHook implements ISessionsRevokedHook {
async execute(metadata) {
await this.auditService.log('sessions_revoked', {
userId: metadata.user.sub,
sessionCount: metadata.sessionCount,
});
}
}

registerUserProfileUpdated()

Register a user profile updated hook provider. Hooks execute after profile attribute changes. Non-blocking - errors are logged.

registerUserProfileUpdated(provider: IUserProfileUpdatedHook): void

Parameters

Example

@Injectable()
@UserProfileUpdatedHook()
export class CrmSyncHook implements IUserProfileUpdatedHook {
async execute(metadata: UserProfileUpdatedMetadata) {
const emailChange = metadata.changedFields.find((f) => f.fieldName === 'email');
if (emailChange) {
await this.crmService.updateContact(metadata.user.sub, {
email: emailChange.newValue,
});
}
}
}

Execution Order

Hooks execute in registration order:

// First hook registered
hookRegistry.registerPreSignup(domainValidation);

// Second hook registered
hookRegistry.registerPreSignup(inviteCodeCheck);

// Execution order during signup:
// 1. domainValidation.execute()
// 2. inviteCodeCheck.execute()

Stopping Execution:

For pre-signup hooks, first hook to throw NAuthException stops execution and blocks signup:

// Hook 1: Throws error
domainValidation.execute(); // Throws PRESIGNUP_FAILED

// Hook 2: Never executes
inviteCodeCheck.execute(); // Skipped

All other hooks are non-blocking:

All hooks execute regardless of errors. Errors are caught and logged:

// Hook 1: Throws error
welcomeEmail.execute(); // Throws error - logged, continues

// Hook 2: Still executes
analytics.execute(); // Executes normally

Error Handling

Pre-Signup Hooks:

  • Errors with code PRESIGNUP_FAILED are re-thrown as-is
  • Other errors are wrapped in PRESIGNUP_FAILED with original message
  • First error stops execution and blocks signup

All Other Hooks:

  • All errors are caught and logged
  • Execution continues to next hook
  • The triggering operation is never blocked