parseBody($request); try { $user = $this->authenticateUser->execute( new AuthenticateUserRequest( email: $body['email'] ?? null, password: $body['password'] ?? null, ), ); } catch (Throwable $exception) { return $this->errorResponse($exception); } $session = $this->createSession->execute($user); $response = $this->jsonResponse( ['user' => $this->buildUserPayload($user)], 200, ); $cookieValue = sprintf( '%s=%s; Expires=%s; Path=/; HttpOnly; SameSite=Lax', AuthMiddleware::COOKIE_NAME, $session->getToken(), $session->getExpiresAt()->format('D, d-M-Y H:i:s T'), ); return $response->withHeader('Set-Cookie', $cookieValue); } public function logout( ServerRequestInterface $request, ): ResponseInterface { $cookies = $request->getCookieParams(); $token = $cookies[AuthMiddleware::COOKIE_NAME] ?? null; if (is_string($token) && $token !== '') { $this->logout->execute($token); } $response = new Response(204); $cookieValue = sprintf( '%s=; Expires=%s; Path=/; HttpOnly; SameSite=Lax', AuthMiddleware::COOKIE_NAME, 'Thu, 01-Jan-1970 00:00:00 GMT', ); return $response->withHeader('Set-Cookie', $cookieValue); } public function me( ServerRequestInterface $request, ): ResponseInterface { $user = $request->getAttribute('user'); if (! $user instanceof User) { return $this->jsonResponse( ['error' => 'unauthenticated'], 401, ); } return $this->jsonResponse( ['user' => $this->buildUserPayload($user)], 200, ); } private function buildUserPayload(User $user): array { return [ 'id' => $user->getId(), 'email' => $user->getEmail()->value(), ]; } private function jsonResponse( array $data, int $status, ): ResponseInterface { $response = new Response($status); $response->getBody()->write(json_encode($data)); return $response->withHeader('Content-Type', 'application/json'); } private function errorResponse(Throwable $exception): ResponseInterface { if ($exception instanceof BadRequestException) { return $this->jsonResponse( ['error' => $exception->getMessage()], 400, ); } if ($exception instanceof UnauthorizedException) { return $this->jsonResponse( ['error' => $exception->getMessage()], 401, ); } if ($exception instanceof DomainException) { return $this->jsonResponse( ['error' => $exception->getMessage()], 409, ); } throw $exception; } private function parseBody(ServerRequestInterface $request): array { $contentType = $request->getHeaderLine('Content-Type'); if (str_contains($contentType, 'application/json')) { $body = (string) $request->getBody(); $decoded = json_decode($body, true); return is_array($decoded) ? $decoded : []; } return (array) $request->getParsedBody(); } }