/** The PKCE + state material minted once per login attempt. */ export interface PkceMaterial { /** Opaque anti-CSRF token echoed back on the loopback callback; verified constant-time. */ state: string; /** The secret the CLI keeps; sent to /exchange. Never leaves the machine until then. */ codeVerifier: string; /** base64url(SHA-256(codeVerifier)); sent to the browser/console, binds the exchange. */ codeChallenge: string; } /** SHA-256 → base64url. Exported for the exchange-binding assertion in tests. */ export declare function s256(input: string): string; /** * Mint fresh `state` + PKCE `code_verifier`/`code_challenge` (S256). The verifier is a * high-entropy 32-byte value (well within RFC 7636's 43–128 char range once base64url'd). */ export declare function makePkceMaterial(): PkceMaterial; /** * Constant-time equality for the returned `state` vs the expected one. Length-mismatched * inputs return false without leaking timing (timingSafeEqual throws on unequal lengths). */ export declare function stateMatches(expected: string, actual: string | null): boolean; /** Prefix a scheme when the user passed a bare host; localhost defaults to http. */ export declare function normalizeBaseUrl(u: string): string; /** * The console URL the browser opens: `/cli-auth?redirect_uri=&state=…&code_challenge=…`. * The console signs the user in (passwordless), shows the Grant CLI access consent screen, * POSTs /access-tokens {code_challenge, state}, and redirects the resulting auth_code to the * loopback. The code_verifier is NOT in this URL — only its challenge. */ export declare function buildCliAuthUrl(consoleBase: string, redirectUri: string, material: PkceMaterial): string; /** A compact, human-copyable fallback URL for the "if it doesn't open" line. */ export declare function shortenUrl(url: string, max?: number): string; export type CallbackResult = { ok: true; code: string; } | { ok: false; reason: "state_mismatch" | "denied" | "missing_code"; message: string; }; /** * Interpret the loopback redirect (`127.0.0.1:PORT?code=…&state=…`). State is verified * constant-time FIRST, always — a mismatch rejects before the code is even read, so a * forged/stray callback can never drive an exchange (QA-F1-C3). The console signals a * user cancel via `?error=access_denied`. */ export declare function parseCallback(params: URLSearchParams, expectedState: string): CallbackResult;