'HS256', 'typ' => 'JWT'])); $payload['iat'] = time(); $payload['exp'] = time() + JWT_TTL; $payload = self::b64e(json_encode($payload)); $sig = self::b64e(hash_hmac('sha256', "$header.$payload", JWT_SECRET, true)); return "$header.$payload.$sig"; } public static function decode(string $token): ?array { $parts = explode('.', $token); if (count($parts) !== 3) return null; [$header, $payload, $sig] = $parts; $expected = self::b64e(hash_hmac('sha256', "$header.$payload", JWT_SECRET, true)); if (!hash_equals($expected, $sig)) return null; $data = json_decode(self::b64d($payload), true); if (!$data || ($data['exp'] ?? 0) < time()) return null; return $data; } private static function b64e(string $v): string { return rtrim(strtr(base64_encode($v), '+/', '-_'), '='); } private static function b64d(string $v): string { return base64_decode(strtr($v, '-_', '+/') . str_repeat('=', (4 - strlen($v) % 4) % 4)); } }