` header. On success the resolved * user row is attached to the request as the `user` attribute. */ final class AuthMiddleware implements MiddlewareInterface { public function __construct( private readonly JwtService $jwt, private readonly UserRepository $users, ) { } public function process(Request $request, RequestHandler $handler): Response { $header = $request->getHeaderLine('Authorization'); if (preg_match('/^Bearer\s+(\S+)$/i', $header, $matches) !== 1) { throw new ApiException('Missing or malformed Authorization header.', 401); } try { $claims = $this->jwt->verify($matches[1]); } catch (Throwable) { throw new ApiException('The access token is invalid or has expired.', 401); } $user = $this->users->findById((int) ($claims['sub'] ?? 0)); if ($user === null) { throw new ApiException('The account for this token no longer exists.', 401); } return $handler->handle($request->withAttribute('user', $user)); } }