Current User
CurrentUserProvider, anonymous identities, request cleanup, and how identity attributes carry JWT claims.
Current User
CurrentUserProvider
Retrieves the current user identity from the request-scoped ArrayAdapter. The identity is set by AuthMiddleware at the start of every request.
use Vortos\Auth\Identity\CurrentUserProvider;
use Vortos\Auth\Contract\UserIdentityInterface;
final class SomeHandler
{
public function __construct(private CurrentUserProvider $currentUser) {}
public function __invoke(SomeCommand $command): void
{
$user = $this->currentUser->get();
if (!$user->isAuthenticated()) {
throw new UnauthorizedException();
}
// $user->id() user ID string
// $user->roles() ['ROLE_USER', 'ROLE_ADMIN']
// $user->hasRole('ROLE_ADMIN') bool
// $user->getAttribute('x') JWT/custom identity attribute
}
}Always returns an identity
get() never returns null. For unauthenticated requests it returns AnonymousIdentity. Always check isAuthenticated() before using the identity on public routes.
$user = $this->currentUser->get();
// Safe pattern:
if (!$user->isAuthenticated()) {
// handle public access
}
// On #[RequiresAuth] controllers, identity is always authenticated:
$userId = $user->id(); // safe, guaranteed authenticatedUserIdentity contract
interface UserIdentityInterface
{
public function id(): string;
public function roles(): array;
public function isAuthenticated(): bool;
public function hasRole(string $role): bool;
public function getAttribute(string $key, mixed $default = null): mixed;
public function getClaims(): array; // what gets serialized into the JWT attrs namespace
}Custom attributes
Anything you pass in the third UserIdentity constructor argument is serialized into the JWT attrs claim and readable on every authenticated request via getAttribute():
// At login — embed in the token:
$identity = new UserIdentity($user->id, $user->roles, [
'organization_id' => $user->organizationId,
'plan' => 'pro',
]);
// Anywhere in the request — read back:
$orgId = $this->currentUser->get()->getAttribute('organization_id');
$plan = $this->currentUser->get()->getAttribute('plan', 'free');getClaims() is what JwtService calls to determine what goes into the token. UserIdentity::getClaims() returns the full attributes array by default. Override it in a custom identity class to exclude fields that should stay in memory only.
Request cleanup
In worker mode, Vortos keeps the compiled container alive between requests. Runner::cleanUp() clears the request-scoped ArrayAdapter after each request so the next request cannot see the previous request's identity.
This is why worker entrypoints must always call cleanup after handling a request.
$runner = new Runner(...);
try {
$response = $runner->run();
$response->send();
} finally {
$runner->cleanUp();
}Why not inject the full User aggregate
Injecting a full User aggregate as "the current user" requires a database query on every request even when the full aggregate is not needed. UserIdentity carries only what is in the JWT, so identity access does not query the database.
When your handler needs the full User aggregate, load it explicitly:
$user = $this->userRepository->findById(
UserId::fromString($this->currentUser->get()->id())
);