Files
pinecore/src/Auth/JwtService.php
2026-04-12 01:40:54 +03:00

71 lines
2.1 KiB
PHP

<?php
namespace Pronchev\Pinecore\Auth;
use DateTimeImmutable;
use Lcobucci\JWT\Configuration;
use Lcobucci\JWT\Signer\Hmac\Sha256;
use Lcobucci\JWT\Signer\Key\InMemory;
use Lcobucci\JWT\Validation\Constraint\SignedWith;
use Lcobucci\JWT\Validation\Constraint\StrictValidAt;
use Pronchev\Pinecore\Config;
use Psr\Clock\ClockInterface;
final class JwtService
{
private readonly Configuration $jwtConfig;
private readonly int $accessTtl;
public function __construct(Config $config)
{
$secret = $config->get('jwt.secret');
if ($secret === '') {
throw new \RuntimeException('JWT_SECRET is not configured');
}
$this->accessTtl = $config->get('jwt.access_ttl');
$signer = new Sha256();
$key = InMemory::plainText($secret);
$jwtConfig = Configuration::forSymmetricSigner($signer, $key);
$this->jwtConfig = $jwtConfig->withValidationConstraints(
new SignedWith($signer, $key),
new StrictValidAt(new class implements ClockInterface {
public function now(): DateTimeImmutable
{
return new DateTimeImmutable();
}
}),
);
}
public function issue(string $userId): string
{
$now = new DateTimeImmutable();
$token = $this->jwtConfig->builder()
->issuedAt($now)
->canOnlyBeUsedAfter($now)
->expiresAt($now->modify("+{$this->accessTtl} seconds"))
->relatedTo($userId)
->getToken($this->jwtConfig->signer(), $this->jwtConfig->signingKey());
return $token->toString();
}
public function verify(string $tokenString): string
{
try {
$token = $this->jwtConfig->parser()->parse($tokenString);
} catch (\Throwable) {
throw new AuthException('Invalid token');
}
if (!$this->jwtConfig->validator()->validate($token, ...$this->jwtConfig->validationConstraints())) {
throw new AuthException('Token validation failed');
}
return $token->claims()->get('sub');
}
}