Newer
Older
gnexus-auth-client-php / src / Runtime / HttpRuntimeUserProvider.php
@Eugene Sukhodolskiy Eugene Sukhodolskiy 12 hours ago 3 KB Initial auth client package scaffold
<?php

declare(strict_types=1);

namespace GNexus\GAuth\Runtime;

use GNexus\GAuth\Config\GAuthConfig;
use GNexus\GAuth\Contract\RuntimeUserProviderInterface;
use GNexus\GAuth\DTO\AuthenticatedUser;
use GNexus\GAuth\DTO\ClientAccess;
use GNexus\GAuth\Exception\RuntimeApiException;
use GNexus\GAuth\Exception\TransportException;
use Psr\Http\Client\ClientExceptionInterface;
use Psr\Http\Client\ClientInterface;
use Psr\Http\Message\RequestFactoryInterface;
use Psr\Log\LoggerInterface;

final readonly class HttpRuntimeUserProvider implements RuntimeUserProviderInterface
{
    public function __construct(
        private GAuthConfig $config,
        private ClientInterface $httpClient,
        private RequestFactoryInterface $requestFactory,
        private ?LoggerInterface $logger = null,
    ) {
    }

    public function fetchUser(string $accessToken): AuthenticatedUser
    {
        $request = $this->requestFactory->createRequest('GET', $this->config->userInfoUrl())
            ->withHeader('Accept', 'application/json')
            ->withHeader('Authorization', sprintf('Bearer %s', $accessToken));

        if ($this->config->userAgent() !== null) {
            $request = $request->withHeader('User-Agent', $this->config->userAgent());
        }

        try {
            $response = $this->httpClient->sendRequest($request);
        } catch (ClientExceptionInterface $exception) {
            $this->logger?->error('gnexus-auth runtime transport failure', [
                'message' => $exception->getMessage(),
            ]);

            throw new TransportException('Request to gnexus-auth runtime API failed.', 0, $exception);
        }

        if ($response->getStatusCode() >= 400) {
            throw new RuntimeApiException('gnexus-auth runtime API returned an error response.');
        }

        $payload = json_decode((string) $response->getBody(), true);

        if (! is_array($payload)) {
            throw new RuntimeApiException('gnexus-auth runtime API returned malformed JSON.');
        }

        $clientAccessList = [];
        $client = $payload['client'] ?? null;

        if (is_array($client) && isset($client['client_id']) && is_string($client['client_id'])) {
            $clientAccessList[] = new ClientAccess(
                clientId: $client['client_id'],
                accessStatus: 'granted',
                roleIds: $this->stringList($client['roles'] ?? []),
                permissionIds: $this->stringList($client['permissions'] ?? []),
            );
        }

        return new AuthenticatedUser(
            userId: (string) ($payload['sub'] ?? $payload['id'] ?? ''),
            email: (string) ($payload['email'] ?? ''),
            emailVerified: (bool) ($payload['email_verified'] ?? false),
            systemRole: isset($payload['system_role']) ? (string) $payload['system_role'] : null,
            status: isset($payload['status']) ? (string) $payload['status'] : null,
            profile: is_array($payload['profile'] ?? null) ? $payload['profile'] : [],
            clientAccessList: $clientAccessList,
            rawPayload: $payload,
        );
    }

    /**
     * @param mixed $value
     * @return array<int, string>
     */
    private function stringList(mixed $value): array
    {
        if (! is_array($value)) {
            return [];
        }

        return array_values(array_map(static fn ($item) => (string) $item, $value));
    }
}