Skip to main content

IPhoneChangedHook

Hook interface for executing actions after a phone number changes.

Overview​

Changing a phone number is destructive to account security: nauth-toolkit clears isPhoneVerified, deletes every SMS MFA device tied to the old number, and switches mfaEnabled off if SMS was the only remaining factor. This hook is how the account owner finds out.

The hook is non-blocking - errors are logged but do not affect the phone change operation.

The alert goes to the account email

The shipped notification is addressed to the user's email, never to either phone number. A phone change is routine, so the mailbox is the stable channel, and notifying the old number fails exactly when it matters: an attacker who changed it no longer controls it.

Interface​

interface IPhoneChangedHook {
execute(metadata: PhoneChangedMetadata): Promise<void>;
}

Metadata​

PhoneChangedMetadata​

interface PhoneChangedMetadata {
user: IUser;
oldPhone: string | null;
newPhone: string;
updateSource: UserProfileUpdateSource;
deactivatedMFADevices?: number;
mfaDisabled?: boolean;
clientInfo?: ClientInfo;
}
PropertyTypeDescription
clientInfoClientInfoIP address, user agent and location of the request that made the change
deactivatedMFADevicesnumberSMS MFA devices deleted because they were tied to the old number
mfaDisabledbooleanTrue when that removal left no factors at all, so mfaEnabled was turned off
newPhonestringPhone number after the change
oldPhonestring | nullPhone number before the change, null when the account had none
updateSourceUserProfileUpdateSource'user_request' or 'admin_action'
userIUserUser whose phone number changed

Usage​

src/hooks/phone-changed.hook.ts
import { IPhoneChangedHook, PhoneChangedMetadata } from '@nauth-toolkit/core';

export class PhoneChangedNotificationHook implements IPhoneChangedHook {
async execute(metadata: PhoneChangedMetadata): Promise<void> {
const { user, newPhone, deactivatedMFADevices, mfaDisabled } = metadata;

await this.alertService.send(user.email, {
newPhone,
removedDevices: deactivatedMFADevices,
mfaNowOff: mfaDisabled,
});
}
}

Register it with HookRegistryService.registerPhoneChanged(), or on NestJS with the @PhoneChangedHook() decorator.

Built-in Notification​

The phoneChanged email template ships with the toolkit and is suppressed by default like every other optional notification. Enable it in config:

src/config/auth.config.ts
emailNotifications: {
enabled: true,
suppress: {
phoneChanged: false,
},
}

See Notifications for the template variables.