Skip to content

Identity Manager

IdentityManager is the contract between the authentication middleware and your application's user store. By default the framework uses a SQL-backed implementation, but you can replace it with your own.

Default SQL implementation

The package ships with DefaultIdentityManager, which uses PDO-backed repositories generated by mvc auth:enable. Register it with:

use PhpMvc\Security\Dependencies;

Dependencies::configure($container);

This binds:

  • IdentityManagerDefaultIdentityManager
  • UserIdentityRepositorySqlUserIdentityRepository
  • SignInSessionRepositorySqlSignInSessionRepository
  • Challenge repositories for sign-up and password reset

The database schema is created by the migration generated via mvc auth:enable.

Custom IdentityManager

To use an external user store (LDAP, OAuth, a different database schema):

  1. Enable authentication without migrations:

    vendor/bin/mvc auth:enable --skip-migrations
    
  2. Implement IdentityManager:

    use PhpMvc\Security\IdentityManager;
    use PhpMvc\Security\Identity;
    
    final class LdapIdentityManager implements IdentityManager
    {
        public function __construct(
            private readonly LdapClient $ldap,
        ) {}
    
        public function getIdentity(?string $token): Identity
        {
            $user = $token !== null ? $this->ldap->findByToken($token) : null;
            return new MyIdentity($user);
        }
    }
    
  3. Register your implementation in the container (instead of calling Dependencies::configure()):

    $container->set(IdentityManager::class, LdapIdentityManager::class);
    

ChallengeNotificator

Dependencies::configure() does not register ChallengeNotificator. The sign-up and password-reset use cases depend on this interface to deliver one-time tokens to the user (by email, SMS, a queue, etc.). You must register a concrete implementation in your composition root:

$container->set(ChallengeNotificator::class, EmailChallengeNotificator::class);

Example: background-task notificator

A common pattern is to enqueue a background task instead of sending email synchronously:

use PhpMvc\Security\Domain\Services\ChallengeNotificator;
use PhpMvc\Security\Domain\Entities\SignUpChallenge;
use PhpMvc\Security\Domain\Entities\ResetPasswordChallenge;
use PhpMvc\BackgroundTasks\Application\RegisterTask\RegisterTask;

final class BackgroundTaskChallengeNotificator implements ChallengeNotificator
{
    public function __construct(
        private readonly RegisterTask $registerTask,
    ) {}

    public function sendSignUpChallenge(string $email, SignUpChallenge $challenge): void
    {
        $this->registerTask->execute(
            type: 'send_sign_up_challenge_email',
            payload: ['email' => $email, 'token' => $challenge->token],
        );
    }

    public function sendResetPasswordChallenge(string $email, ResetPasswordChallenge $challenge): void
    {
        $this->registerTask->execute(
            type: 'send_reset_password_challenge_email',
            payload: ['email' => $email, 'token' => $challenge->token],
        );
    }
}

Identity interface

Your identity object must implement the Identity contract:

interface Identity
{
    public function isAuthenticated(): bool;
    public function username(): string;
    public function getRoles(): array;
    public function hasRole(string $role): bool;
}

getRoles() is used by the Authorization middleware to enforce route-level role restrictions.