'JWT', 'alg' => 'HS256']; $payload['iat'] = time(); $payload['exp'] = time() + $config['jwt_ttl']; $segments = [ self::base64Url(json_encode($header)), self::base64Url(json_encode($payload)), ]; $signature = hash_hmac('sha256', implode('.', $segments), $config['jwt_secret'], true); $segments[] = self::base64Url($signature); return implode('.', $segments); } public static function decode(string $token): ?array { $config = require __DIR__ . '/../../config/app.php'; $parts = explode('.', $token); if (count($parts) !== 3) { return null; } [$header, $payload, $signature] = $parts; $expected = self::base64Url(hash_hmac('sha256', "$header.$payload", $config['jwt_secret'], true)); if (!hash_equals($expected, $signature)) { return null; } $data = json_decode(self::base64UrlDecode($payload), true); if (!is_array($data) || ($data['exp'] ?? 0) < time()) { return null; } return $data; } private static function base64Url(string $value): string { return rtrim(strtr(base64_encode($value), '+/', '-_'), '='); } private static function base64UrlDecode(string $value): string { return base64_decode(strtr($value, '-_', '+/')) ?: ''; } }