[ AzureExtendSocialite::class.'@handle', AuthentikExtendSocialite::class.'@handle', ClerkExtendSocialite::class.'@handle', DiscordExtendSocialite::class.'@handle', GoogleExtendSocialite::class.'@handle', InfomaniakExtendSocialite::class.'@handle', ZitadelExtendSocialite::class.'@handle', ], ]; public function boot(): void { Event::listen(Login::class, function (Login $event): void { auditLog('auth.user.login_succeeded', $this->authContext($event->user)); }); Event::listen(Failed::class, function (Failed $event): void { auditLog('auth.user.login_failed', [ 'attempted_email' => $this->attemptedEmailForAudit(data_get($event->credentials, 'email')), 'guard' => $event->guard, ], 'warning'); }); Event::listen(Logout::class, function (Logout $event): void { auditLog('auth.user.logged_out', $this->authContext($event->user)); }); Event::listen(Registered::class, function (Registered $event): void { auditLog('auth.user.registered', $this->authContext($event->user)); }); Event::listen(Verified::class, function (Verified $event): void { auditLog('auth.user.email_verified', $this->authContext($event->user)); }); Event::listen(PasswordReset::class, function (PasswordReset $event): void { auditLog('auth.user.password_reset', $this->authContext($event->user)); }); Event::listen(TwoFactorAuthenticationEnabled::class, function (TwoFactorAuthenticationEnabled $event): void { auditLog('auth.user.two_factor_enabled', $this->authContext($event->user)); }); Event::listen(TwoFactorAuthenticationConfirmed::class, function (TwoFactorAuthenticationConfirmed $event): void { auditLog('auth.user.two_factor_confirmed', $this->authContext($event->user)); }); Event::listen(TwoFactorAuthenticationDisabled::class, function (TwoFactorAuthenticationDisabled $event): void { auditLog('auth.user.two_factor_disabled', $this->authContext($event->user)); }); Event::listen(RecoveryCodesGenerated::class, function (RecoveryCodesGenerated $event): void { auditLog('auth.user.recovery_codes_regenerated', $this->authContext($event->user)); }); Event::listen(PasskeyRegistered::class, function (PasskeyRegistered $event): void { auditLog('auth.user.passkey_registered', $this->authContext($event->user)); }); Event::listen(PasskeyVerified::class, function (PasskeyVerified $event): void { auditLog('auth.user.passkey_verified', $this->authContext($event->user)); }); Event::listen(PasskeyDeleted::class, function (PasskeyDeleted $event): void { auditLog('auth.user.passkey_deleted', $this->authContext($event->user)); }); } /** * Users sometimes type a password into the email field, so only a valid email address is stored. */ private function attemptedEmailForAudit(mixed $email): ?string { if (blank($email)) { return null; } return is_string($email) && filter_var($email, FILTER_VALIDATE_EMAIL) !== false ? $email : '[invalid]'; } private function authContext(?object $user): array { return [ 'team_id' => $user?->currentTeam()?->id, 'resource' => 'user', 'user_name' => $user?->name, 'actor_id' => $user?->id, 'actor_name' => $user?->name, 'actor_email' => $user?->email, ]; } public function shouldDiscoverEvents(): bool { return true; } }