57 lines
1.3 KiB
PHP
57 lines
1.3 KiB
PHP
<?php
|
|||
|
|
|
||
|
|
declare(strict_types=1);
|
||
|
|
|
||
|
|
namespace App\Auth;
|
||
|
|
|
||
|
|
use Firebase\JWT\JWT;
|
||
|
|
use Firebase\JWT\Key;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Issues and verifies stateless HS256 JSON Web Tokens for authenticated users.
|
||
|
|
*/
|
||
|
|
final class JwtService
|
||
|
|
{
|
||
|
|
private const ALGORITHM = 'HS256';
|
||
|
|
|
||
|
|
public function __construct(
|
||
|
|
private readonly string $secret,
|
||
|
|
private readonly int $ttl,
|
||
|
|
) {
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @param array{id: int, email: string, ...} $user
|
||
|
|
* @return array{token: string, expires_at: string}
|
||
|
|
*/
|
||
|
|
public function issue(array $user): array
|
||
|
|
{
|
||
|
|
$issuedAt = time();
|
||
|
|
$expiresAt = $issuedAt + $this->ttl;
|
||
|
|
|
||
|
|
$token = JWT::encode([
|
||
|
|
'sub' => (int) $user['id'],
|
||
|
|
'email' => $user['email'],
|
||
|
|
'iat' => $issuedAt,
|
||
|
|
'exp' => $expiresAt,
|
||
|
|
], $this->secret, self::ALGORITHM);
|
||
|
|
|
||
|
|
return [
|
||
|
|
'token' => $token,
|
||
|
|
'expires_at' => gmdate('c', $expiresAt),
|
||
|
|
];
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @return array<string, mixed> The decoded claims.
|
||
|
|
*
|
||
|
|
* @throws \Firebase\JWT\ExpiredException
|
||
|
|
* @throws \Firebase\JWT\SignatureInvalidException
|
||
|
|
* @throws \UnexpectedValueException
|
||
|
|
*/
|
||
|
|
public function verify(string $token): array
|
||
|
|
{
|
||
|
|
return (array) JWT::decode($token, new Key($this->secret, self::ALGORITHM));
|
||
|
|
}
|
||
|
|
}
|