/** * Persistence layer for the human user's OAuth2 tokens obtained via PKCE * login. * * Tokens live in the `user.oauth2` block of the shared config file at * ~/.config/ory-agent-plugins/config.json. Reads use loadConfig(); writes * go through mutateConfig() so the existing lockfile and atomic-rename * machinery covers concurrent processes. * * In addition, this module provides a pkce-flight lock so that when two * agent processes start simultaneously and neither has tokens yet, only * one opens a browser and the others poll for the result. */ import { type OryOAuth2Tokens } from "./config.js"; /** Load the user's OAuth2 tokens from the persisted config file, if any. */ export declare function loadTokens(): OryOAuth2Tokens | undefined; /** Persist the user's OAuth2 tokens. Existing tokens are replaced atomically. */ export declare function saveTokens(tokens: OryOAuth2Tokens): void; /** Remove the user's persisted OAuth2 tokens. */ export declare function clearTokens(): void; /** * A user credential supplied out-of-band through the environment (CI, scripted * runs, a harness launched by a wrapper that already authenticated). */ export interface EnvUserCredential { /** The bearer, if any of the four accepted variables is set. */ token?: string; /** `ORY_USER_SUBJECT_ID`, when the operator pinned the subject. */ subject?: string; } /** * Read the pre-supplied user credential from the environment. * * **`ORY_USER_OAUTH2_TOKEN` is the only accepted variable**, because an OAuth2 * access token is the only thing the credential is ever used as. All three * consumers of `userPrincipal.token` demand one: broker delegation * authentication and the agent + sub-agent DCR bootstraps (which send it as a * bearer to `/oauth2/register`). Nothing calls `verifySession`, so a Kratos * session token is never consumed as a session token. * * Three variables used to be accepted alongside it and have been removed: * `ORY_USER_SESSION_TOKEN` (plus its legacy alias `ORY_SESSION_TOKEN`) named a * Kratos session token and took *first* precedence, so supplying the credential * its name asked for made every permission check fail `session_inactive` — and * beat the variable that would have worked. `ORY_OAUTH2_TOKEN` was a redundant * legacy alias. Pin the subject with `ORY_USER_SUBJECT_ID`. * * This lives here, and only here, because two call sites depend on agreeing: * the login gate's `env_token` short-circuit (which runs on `SessionStart`) and * the per-client rehydration in `OryAgentClient.fromEnv` (which runs on *every* * lifecycle event, including the subprocess tool-call events where the gate * never runs). If those disagreed, an env-supplied token would authenticate the * session and then silently stop authenticating the permission checks. */ export declare function readEnvUserCredential(env?: NodeJS.ProcessEnv): EnvUserCredential; /** Number of seconds before nominal expiry that we consider tokens stale. */ export declare const TOKEN_EXPIRY_SKEW_SEC = 60; /** Returns true if the access token is missing or within the skew window of expiry. */ export declare function isExpired(tokens: OryOAuth2Tokens, now?: number): boolean; /** * Refresh the persisted tokens using their refresh_token. Saves the * resulting tokens back to disk. Throws if no refresh token is available * or if the refresh call fails. */ export declare function refreshAndSave(args: { projectUrl: string; clientId: string; current: OryOAuth2Tokens; }): Promise; export interface PkceFlightLock { release: () => void; } /** * Try to acquire the pkce-flight lock. Returns the lock handle if this * caller is the leader (and should run the browser flow), or null if * another process already holds the lock. * * The lock is a sibling file containing the holder's PID. A lock is * considered stale (and reclaimed automatically) when either of these is * true: * * - the PID written in the file is no longer a live process, or * - the file is older than 5 minutes * * PID-liveness is the primary signal — it catches crashed / killed * processes immediately so the next launch isn't stuck waiting. The age * check is a fallback for the cross-host case (PID is meaningful only on * the host that wrote it) and for PID reuse edge cases. */ export declare function tryAcquirePkceFlightLock(): PkceFlightLock | null; /** * Unconditionally remove the pkce-flight lock, if any. Use this from * single-owner maintenance contexts where no peer is mid-flow. Returns true * when a lock was removed. */ export declare function clearPkceFlightLock(): boolean; /** * Block until another process completes the PKCE flow and writes tokens, * or until the timeout elapses. Returns the tokens if they appeared in * time, or null otherwise. */ export declare function waitForPeerTokens(opts?: { timeoutMs?: number; pollIntervalMs?: number; }): Promise; /** Synchronous variant for callers that already block on the file system. */ export declare function waitForPeerTokensSync(opts?: { timeoutMs?: number; pollIntervalMs?: number; }): OryOAuth2Tokens | null;