### Install AuthLogBundle via Composer Source: https://github.com/spiriitlabs/auth-log-bundle/blob/main/README.md Run this command in your project root to add the bundle dependency. ```bash composer require spiriitlabs/auth-log-bundle ``` -------------------------------- ### Listen to NEW_DEVICE Events Source: https://github.com/spiriitlabs/auth-log-bundle/blob/main/README.md Implement an event listener to handle custom logic when a new device or context is detected. ```php use Spiriit\Bundle\AuthLogBundle\Listener\AuthenticationLogEvent; use Spiriit\Bundle\AuthLogBundle\Listener\AuthenticationLogEvents; use Symfony\Component\EventDispatcher\Attribute\AsEventListener; #[AsEventListener(event: AuthenticationLogEvents::NEW_DEVICE)] final class NewDeviceListener { public function __invoke(AuthenticationLogEvent $event): void { $userIdentifier = $event->userIdentifier(); $userInformation = $event->userInformation(); // your custom logic here } } ``` -------------------------------- ### Implement Authentication Log Repository Source: https://github.com/spiriitlabs/auth-log-bundle/blob/main/README.md Create a repository that implements AuthenticationLogRepositoryInterface and AuthenticationLogCreatorInterface to handle log persistence and creation. ```php use Doctrine\ORM\EntityRepository; use Spiriit\Bundle\AuthLogBundle\AuthenticationLog\AuthenticationLogCreatorInterface; use Spiriit\Bundle\AuthLogBundle\Entity\AuthenticationLogInterface; use Spiriit\Bundle\AuthLogBundle\FetchUserInformation\UserInformation; use Spiriit\Bundle\AuthLogBundle\Repository\AuthenticationLogRepositoryInterface; class UserAuthLogRepository extends EntityRepository implements AuthenticationLogRepositoryInterface, AuthenticationLogCreatorInterface { public function save(AuthenticationLogInterface $log): void { $this->getEntityManager()->persist($log); $this->getEntityManager()->flush(); } public function findExistingLog(string $userIdentifier, UserInformation $userInformation): bool { return null !== $this->findOneBy([ 'user' => $userIdentifier, 'ipAddress' => $userInformation->ipAddress, ]); } public function createLog(string $userIdentifier, UserInformation $userInformation): AuthenticationLogInterface { $user = $this->getEntityManager()->getRepository(User::class)->findOneBy([ 'email' => $userIdentifier, ]); return new UserAuthLog($user, $userInformation); } } ``` -------------------------------- ### Enable Login Confirmation Feature Source: https://github.com/spiriitlabs/auth-log-bundle/blob/main/README.md Configure the bundle to enable confirmation links and set the token expiration time. ```yaml spiriit_auth_log: confirmation: enabled: true token_ttl: '3 days' # relative expression: "12 hours", "1 week"... ``` -------------------------------- ### Expose Confirmation Routes Source: https://github.com/spiriitlabs/auth-log-bundle/blob/main/README.md Configure the confirmation route by either importing the default bundle route or defining a custom one. ```yaml # config/routes/spiriit_auth_log.yaml spiriit_auth_log: resource: '@SpiriitAuthLogBundle/config/routes.php' prefix: /security # optional ``` ```yaml # config/routes.yaml my_login_confirmation: path: /account/logins/{action}/{token} controller: spiriit_auth_log.confirmation_controller methods: [GET, POST] requirements: { action: 'acknowledge|disavow' } ``` ```yaml spiriit_auth_log: confirmation: enabled: true route_name: my_login_confirmation # defaults to "spiriit_auth_log_confirm" ``` -------------------------------- ### Run development and testing commands Source: https://github.com/spiriitlabs/auth-log-bundle/blob/main/README.md Use these Composer scripts to execute the test suite, verify code style, and perform static analysis. ```bash composer test # Run the test suite composer cs-check # Check code style (dry-run) composer cs-fix # Fix code style vendor/bin/phpstan analyse # Static analysis ``` -------------------------------- ### Configure Geolocation Providers Source: https://github.com/spiriitlabs/auth-log-bundle/blob/main/README.md Set up GeoIP2 with a local database path or use the external IP API provider. ```yaml spiriit_auth_log: location: provider: 'geoip2' geoip2_database_path: '%kernel.project_dir%/var/GeoLite2-City.mmdb' ``` ```yaml spiriit_auth_log: location: provider: 'ipApi' ``` -------------------------------- ### Handle Confirmation Events Source: https://github.com/spiriitlabs/auth-log-bundle/blob/main/README.md Create an event listener to react to login acknowledgment or disavowal events. ```php use Spiriit\Bundle\AuthLogBundle\Listener\AuthenticationLogConfirmationEvent; use Spiriit\Bundle\AuthLogBundle\Listener\AuthenticationLogEvents; use Symfony\Component\EventDispatcher\Attribute\AsEventListener; #[AsEventListener(event: AuthenticationLogEvents::LOGIN_DISAVOWED)] final class LoginDisavowedListener { public function __invoke(AuthenticationLogConfirmationEvent $event): void { $log = $event->authenticationLog(); $user = $log->getUser(); // e.g. force a password reset, invalidate sessions, notify security... } } ``` -------------------------------- ### Configure Messenger Bus and Routing Source: https://github.com/spiriitlabs/auth-log-bundle/blob/main/README.md Enable the messenger bus and optionally route the AuthLoginMessage to an async transport. ```yaml spiriit_auth_log: messenger: 'messenger.default_bus' ``` ```yaml framework: messenger: routing: 'Spiriit\Bundle\AuthLogBundle\Messenger\AuthLoginMessage\AuthLoginMessage': async ``` -------------------------------- ### Implement Confirmable Repository Source: https://github.com/spiriitlabs/auth-log-bundle/blob/main/README.md Update your repository to implement the ConfirmableAuthenticationLogRepositoryInterface and provide a lookup method for tokens. ```php use Spiriit\Bundle\AuthLogBundle\Entity\ConfirmableAuthenticationLogInterface; use Spiriit\Bundle\AuthLogBundle\Repository\ConfirmableAuthenticationLogRepositoryInterface; class UserAuthLogRepository extends EntityRepository implements AuthenticationLogRepositoryInterface, AuthenticationLogCreatorInterface, ConfirmableAuthenticationLogRepositoryInterface { // ... existing methods public function findOneByConfirmationToken(string $confirmationToken): ?ConfirmableAuthenticationLogInterface { return $this->findOneBy(['confirmationToken' => $confirmationToken]); } } ``` -------------------------------- ### YAML Configuration Structure Source: https://github.com/spiriitlabs/auth-log-bundle/blob/main/UPGRADE.md The configuration structure remains unchanged in this version. ```yaml spiriit_auth_log: messenger: false transports: mailer: 'mailer' sender_email: 'no-reply@yourdomain.com' sender_name: 'Your App Security' location: provider: 'ipApi' # or 'geoip2' or null ``` -------------------------------- ### Implement Confirmable Authentication Log Entity Source: https://github.com/spiriitlabs/auth-log-bundle/blob/main/README.md Add the required trait and interface to your authentication log entity to support confirmation tokens. ```php use Spiriit\Bundle\AuthLogBundle\Entity\AbstractAuthenticationLog; use Spiriit\Bundle\AuthLogBundle\Entity\ConfirmableAuthenticationLogInterface; use Spiriit\Bundle\AuthLogBundle\Entity\ConfirmableAuthenticationLogTrait; #[ORM\Entity(repositoryClass: UserAuthLogRepository::class)] class UserAuthLog extends AbstractAuthenticationLog implements ConfirmableAuthenticationLogInterface { use ConfirmableAuthenticationLogTrait; // ... your existing fields } ``` -------------------------------- ### Replace Factory with Repository Source: https://github.com/spiriitlabs/auth-log-bundle/blob/main/UPGRADE.md Remove the AuthenticationLogFactoryInterface implementation and replace it with a repository implementing AuthenticationLogRepositoryInterface and AuthenticationLogCreatorInterface. ```php use Spiriit\Bundle\AuthLogBundle\AuthenticationLogFactory\AuthenticationLogFactoryInterface; class UserAuthLogFactory implements AuthenticationLogFactoryInterface { public function supports(): string { return 'user'; } public function createUserReference(string $userIdentifier): UserReference { /* ... */ } public function isKnown(UserReference $userReference): bool { /* ... */ } } ``` ```php use Doctrine\ORM\EntityRepository; use Spiriit\Bundle\AuthLogBundle\AuthenticationLog\AuthenticationLogCreatorInterface; use Spiriit\Bundle\AuthLogBundle\Entity\AbstractAuthenticationLog; use Spiriit\Bundle\AuthLogBundle\FetchUserInformation\UserInformation; use Spiriit\Bundle\AuthLogBundle\Repository\AuthenticationLogRepositoryInterface; class UserAuthLogRepository extends EntityRepository implements AuthenticationLogRepositoryInterface, AuthenticationLogCreatorInterface { public function save(AbstractAuthenticationLog $log): void { $this->getEntityManager()->persist($log); $this->getEntityManager()->flush(); } public function findExistingLog(string $userIdentifier, UserInformation $userInformation): bool { return null !== $this->findOneBy([ 'user' => $userIdentifier, 'ipAddress' => $userInformation->ipAddress, ]); } public function createLog(string $userIdentifier, UserInformation $userInformation): AbstractAuthenticationLog { // Build and return your entity return new UserAuthLog($userIdentifier, $userInformation); } } ``` -------------------------------- ### Implement Custom Notification Interface Source: https://github.com/spiriitlabs/auth-log-bundle/blob/main/README.md Create a class implementing NotificationInterface to handle custom transports like Slack or SMS. ```php use Spiriit\Bundle\AuthLogBundle\Confirmation\ConfirmationLinks; use Spiriit\Bundle\AuthLogBundle\DTO\UserReference; use Spiriit\Bundle\AuthLogBundle\FetchUserInformation\UserInformation; use Spiriit\Bundle\AuthLogBundle\Notification\NotificationInterface; final class SlackNotification implements NotificationInterface { public function send(UserInformation $userInformation, UserReference $userReference, ?ConfirmationLinks $confirmationLinks = null): void { // send a Slack message, SMS, etc. // $confirmationLinks is null unless the confirmation feature is enabled } } ``` -------------------------------- ### Update Repository Interface Signatures Source: https://github.com/spiriitlabs/auth-log-bundle/blob/main/UPGRADE.md Update save() and createLog() methods to type-hint AuthenticationLogInterface instead of AbstractAuthenticationLog. ```php use Spiriit\Bundle\AuthLogBundle\Entity\AbstractAuthenticationLog; class UserAuthLogRepository extends EntityRepository implements AuthenticationLogRepositoryInterface, AuthenticationLogCreatorInterface { public function save(AbstractAuthenticationLog $log): void { $this->getEntityManager()->persist($log); $this->getEntityManager()->flush(); } public function createLog(string $userIdentifier, UserInformation $userInformation): AbstractAuthenticationLog { return new UserAuthLog($userIdentifier, $userInformation); } } ``` ```php use Spiriit\Bundle\AuthLogBundle\Entity\AuthenticationLogInterface; class UserAuthLogRepository extends EntityRepository implements AuthenticationLogRepositoryInterface, AuthenticationLogCreatorInterface { public function save(AuthenticationLogInterface $log): void { $this->getEntityManager()->persist($log); $this->getEntityManager()->flush(); } public function createLog(string $userIdentifier, UserInformation $userInformation): AuthenticationLogInterface { return new UserAuthLog($userIdentifier, $userInformation); } } ``` -------------------------------- ### Configure AuthLogBundle Source: https://github.com/spiriitlabs/auth-log-bundle/blob/main/README.md Define the email sender settings in your Symfony configuration file. ```yaml # config/packages/spiriit_auth_log.yaml spiriit_auth_log: transports: sender_email: 'no-reply@yourdomain.com' sender_name: 'Security' ``` -------------------------------- ### Create Authentication Log Entity Source: https://github.com/spiriitlabs/auth-log-bundle/blob/main/README.md Extend AbstractAuthenticationLog to define your custom log entity and its relation to the User. ```php use Doctrine\ORM\Mapping as ORM; use Spiriit\Bundle\AuthLogBundle\Entity\AbstractAuthenticationLog; use Spiriit\Bundle\AuthLogBundle\Entity\AuthLogUserInterface; use Spiriit\Bundle\AuthLogBundle\FetchUserInformation\UserInformation; #[ORM\Entity(repositoryClass: UserAuthLogRepository::class)] class UserAuthLog extends AbstractAuthenticationLog { #[ORM\Id, ORM\GeneratedValue, ORM\Column] private ?int $id = null; #[ORM\ManyToOne(targetEntity: User::class)] private User $user; public function __construct(User $user, UserInformation $userInformation) { $this->user = $user; parent::__construct($userInformation); } public function getUser(): AuthLogUserInterface { return $this->user; } } ``` -------------------------------- ### Configure Default URI for Messenger Source: https://github.com/spiriitlabs/auth-log-bundle/blob/main/README.md Set the default URI in routing configuration to allow absolute URL generation from background workers. ```yaml # config/packages/routing.yaml framework: router: default_uri: 'https://your-domain.com' ``` -------------------------------- ### Implement AuthLogUserInterface Source: https://github.com/spiriitlabs/auth-log-bundle/blob/main/README.md Update your User entity to implement AuthLogUserInterface for email and display name retrieval. ```php use Spiriit\Bundle\AuthLogBundle\Entity\AuthLogUserInterface; class User implements AuthLogUserInterface { // ... your existing User fields public function getAuthLogEmail(): string { return $this->email; } public function getAuthLogDisplayName(): string { return $this->name; } } ``` -------------------------------- ### Override Email Template Path Source: https://github.com/spiriitlabs/auth-log-bundle/blob/main/README.md Define the custom template file path within the project structure. ```text templates/bundles/SpiriitAuthLogBundle/new_device.html.twig ``` -------------------------------- ### Configure Custom Mailer Transport Source: https://github.com/spiriitlabs/auth-log-bundle/blob/main/README.md Register the custom notification service in the bundle configuration. ```yaml spiriit_auth_log: transports: mailer: 'App\Notification\SlackNotification' sender_email: 'no-reply@yourdomain.com' sender_name: 'Security' ``` -------------------------------- ### Remove Manual Event Listener Source: https://github.com/spiriitlabs/auth-log-bundle/blob/main/UPGRADE.md Delete custom event listeners that manually persist logs, as the bundle now handles this automatically. Update any remaining listeners to use the new event methods. ```php class AuthLogListener { public function onNewDevice(AuthenticationLogEvent $event): void { // persist the log... $event->markAsHandled(); } } ``` ```php use Spiriit\Bundle\AuthLogBundle\Listener\AuthenticationLogEvent; use Spiriit\Bundle\AuthLogBundle\Listener\AuthenticationLogEvents; // Event methods changed: $event->userIdentifier(); // was: getUserReference() $event->userInformation(); // was: getUserInformation() // Removed: // $event->markAsHandled() — no longer exists // $event->isLogHandled() — no longer exists ``` -------------------------------- ### Update Custom Handler Return Type Source: https://github.com/spiriitlabs/auth-log-bundle/blob/main/UPGRADE.md Update the handle() method signature to return AuthenticationLogInterface instead of void. ```php // Before public function handle(string $userIdentifier, UserInformation $userInformation): void ``` ```php // After public function handle(string $userIdentifier, UserInformation $userInformation): AuthenticationLogInterface ``` -------------------------------- ### Update User Entity Interface Source: https://github.com/spiriitlabs/auth-log-bundle/blob/main/UPGRADE.md Replace AuthenticableLogInterface with AuthLogUserInterface in your User entity. Note that AuthLogUserInterface extends UserInterface, so explicit declaration is no longer required. ```php use Spiriit\Bundle\AuthLogBundle\Entity\AuthenticableLogInterface; use Symfony\Component\Security\Core\User\UserInterface; class User implements UserInterface, AuthenticableLogInterface { public function getAuthenticationLogFactoryName(): string { return 'user'; } public function getAuthenticationLogsToEmail(): string { return $this->email; } public function getAuthenticationLogsToEmailName(): string { return $this->displayName; } } ``` ```php use Spiriit\Bundle\AuthLogBundle\Entity\AuthLogUserInterface; class User implements AuthLogUserInterface { public function getAuthLogEmail(): string { return $this->email; } public function getAuthLogDisplayName(): string { return $this->displayName; } } ``` -------------------------------- ### Update Custom Notification Signature Source: https://github.com/spiriitlabs/auth-log-bundle/blob/main/UPGRADE.md Add the optional ConfirmationLinks parameter to the send() method in custom notification implementations. ```php use Spiriit\Bundle\AuthLogBundle\Notification\NotificationInterface; final class SlackNotification implements NotificationInterface { public function send(UserInformation $userInformation, UserReference $userReference): void { // ... } } ``` ```php use Spiriit\Bundle\AuthLogBundle\Confirmation\ConfirmationLinks; use Spiriit\Bundle\AuthLogBundle\Notification\NotificationInterface; final class SlackNotification implements NotificationInterface { public function send(UserInformation $userInformation, UserReference $userReference, ?ConfirmationLinks $confirmationLinks = null): void { // Use $confirmationLinks->acknowledgeUrl / ->disavowUrl when not null } } ``` -------------------------------- ### Update Authentication Log Entity Return Type Source: https://github.com/spiriitlabs/auth-log-bundle/blob/main/UPGRADE.md Update the return type of the getUser method in your authentication log entity to use AuthLogUserInterface. ```php use Spiriit\Bundle\AuthLogBundle\Entity\AbstractAuthenticationLog; use Spiriit\Bundle\AuthLogBundle\Entity\AuthenticableLogInterface; class UserAuthLog extends AbstractAuthenticationLog { public function getUser(): AuthenticableLogInterface { return $this->user; } } ``` ```php use Spiriit\Bundle\AuthLogBundle\Entity\AbstractAuthenticationLog; use Spiriit\Bundle\AuthLogBundle\Entity\AuthLogUserInterface; class UserAuthLog extends AbstractAuthenticationLog { public function getUser(): AuthLogUserInterface { return $this->user; } } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.