jwtSecret = $_ENV['JWT_SECRET'] ?? ''; } public function __invoke(ServerRequestInterface $request, callable $next) { if ($this->jwtSecret === '') { // Configuração ausente é erro de servidor, não de autenticação. Logger::error('JWT_SECRET is not configured; rejecting authenticated request'); return Payload::fail('Internal server error', [], 'E_GENERIC', 500); } $authHeader = $request->getHeaderLine('Authorization'); if (empty($authHeader) || !preg_match('/Bearer\s+(.*)/', $authHeader, $matches)) { return Payload::fail('Unauthorized', [], 'E_VALIDATE', 401); } $token = $matches[1]; try { $decoded = JWT::decode($token, new Key($this->jwtSecret, 'HS256')); $userId = $decoded->sub ?? null; $userEmail = $decoded->email ?? $decoded->username ?? null; if (empty($userId) || empty($userEmail)) { return Payload::fail('Unauthorized', [], 'E_VALIDATE', 401); } $pdo = Database::pdo(); $stmt = $pdo->prepare("SELECT user_id, user_email FROM \"user\" WHERE user_id = :user_id AND user_email = :user_email AND user_deleted_at = 'infinity'"); $stmt->execute(['user_id' => $userId, 'user_email' => mb_strtolower(trim($userEmail))]); $user = $stmt->fetch(\PDO::FETCH_ASSOC); if (!$user) { return Payload::fail('Unauthorized', [], 'E_VALIDATE', 401); } $request = $request ->withAttribute('api_user', $user['user_email']) ->withAttribute('api_user_id', $user['user_id']) ->withAttribute('user_email', $user['user_email']) ->withAttribute('user_id', $user['user_id']); return $next($request); } catch (\Exception $e) { // Detalhe do erro vai só para o log; cliente recebe mensagem genérica. Logger::warning('JWT authentication failed', ['error' => $e->getMessage()]); return Payload::fail('Unauthorized', [], 'E_VALIDATE', 401); } } }