'JWT', 'alg' => 'HS256']); $base64UrlHeader = self::base64UrlEncode($header); $base64UrlPayload = self::base64UrlEncode(json_encode($payload)); $signature = hash_hmac('sha256', $base64UrlHeader . "." . $base64UrlPayload, $secret, true); $base64UrlSignature = self::base64UrlEncode($signature); return $base64UrlHeader . "." . $base64UrlPayload . "." . $base64UrlSignature; } public static function decode(string $token, string $secret): ?array { $parts = explode('.', $token); if (count($parts) !== 3) return null; [$header, $payload, $signature] = $parts; $expectedSignature = self::base64UrlEncode(hash_hmac('sha256', $header . "." . $payload, $secret, true)); if (!hash_equals($expectedSignature, $signature)) return null; $decodedPayload = json_decode(self::base64UrlDecode($payload), true); // Check expiry if (isset($decodedPayload['exp']) && $decodedPayload['exp'] < time()) return null; return $decodedPayload; } }