'JWT', 'alg' => 'HS256'])); $payload['exp'] = time() + $expire; $payload['iat'] = time(); $body = self::base64UrlEncode(json_encode($payload)); $signature = self::base64UrlEncode(hash_hmac('sha256', "{$header}.{$body}", $secret, true)); return "{$header}.{$body}.{$signature}"; } public static function verifyToken(?string $token): ?array { if (!$token) { return null; } if (str_starts_with($token, 'Bearer ')) { $token = substr($token, 7); } $parts = explode('.', $token); if (count($parts) !== 3) { return null; } [$header, $body, $signature] = $parts; $secret = config('jwt.secret'); $expected = self::base64UrlEncode(hash_hmac('sha256', "{$header}.{$body}", $secret, true)); if (!hash_equals($expected, $signature)) { return null; } $payload = json_decode(self::base64UrlDecode($body), true); if (!$payload || ($payload['exp'] ?? 0) < time()) { return null; } return $payload; } private static function base64UrlEncode(string $data): string { return rtrim(strtr(base64_encode($data), '+/', '-_'), '='); } private static function base64UrlDecode(string $data): string { return base64_decode(strtr($data, '-_', '+/')); } }