/** * User login. Orchestrates the "first interaction must * authenticate the human user" requirement across all plugins: * * 1. Resolve config (env + ~/.config/ory-agent-plugins/config.json). * 2. If no project URL, prompt for one when a TTY is available; * otherwise skip with an audit event. * 3. If a session/oauth2 token is already in env, short-circuit ok. * 4. If persisted tokens are valid, return ok. * 5. If they are expired with a refresh_token, refresh. * 6. Otherwise launch the PKCE browser login. The flow prints the * authorize URL to stderr and waits on a loopback callback, so a * missing TTY is fine — users without an interactive terminal can * paste the URL into any browser that can reach 127.0.0.1. Only * truly unattended (CI=true) environments short-circuit early. * * Every terminal path emits exactly one `user.auth` activity event so that * the audit trail is complete regardless of outcome. * * The flow runs on **every** session and is **never** blocking: it * establishes or refreshes the user identity for attribution, delegation, * and permission-subject resolution, but a failure to authenticate never * stops the session. Enforcement is governed solely by `permissionMode` * (observe/enforce) at tool-call time — see `checkAndDecide`. The one * exception is Agent Security not being connected at all (no project URL * and OAuth2 client id), in which case there is nothing to sign in to and * the flow no-ops with mode `not_connected`. When the user can't be * authenticated the session still * proceeds; under `enforce` a missing user identity naturally denies at * the tool (no matching tuples), and under `observe` it is audited. * * This authenticates the *user* (the human at the keyboard). The * separate agent identity (the AI process making the calls) is resolved * non-interactively via env-configured machine credentials and is not * handled here — see `ensureAgentIdentity`. */ import { OryAgentClient } from "./client.js"; import { type OryOAuth2Tokens } from "./config.js"; import { pkceLogin } from "./auth.js"; export type UserLoginMode = "not_connected" | "env_token" | "ok" | "refreshed" | "skipped" | "declined" | "error"; export interface UserLoginOptions { /** Bin name used in user-facing prompts (e.g. "ory-claude"). */ binName: string; /** Logical harness name used for activity attribution. */ harness: string; /** * Optional override of the PKCE login function — used by tests and by * harnesses that want to plug in a different flow. */ loginFn?: typeof pkceLogin; /** Override TTY detection (for tests). */ isTtyAvailableFn?: () => boolean; } export interface UserLoginDecision { /** * Whether the caller should let the session proceed. User authentication * is non-blocking, so this is **always** `true` — it is retained so the * session-start adapters keep a stable shape. Enforcement lives in * `permissionMode` at tool-call time, not here. */ proceed: boolean; /** Stable mode identifier for activity logging and tests. */ mode: UserLoginMode; /** Human-readable reason; safe to surface to the operator. */ reason: string; /** Subject (sub claim) when authenticated. */ subject?: string; } /** * The entry point that every plugin's session-start handler should call * to authenticate the human user. Always returns a decision; never throws. */ export declare function ensureUserAuthenticated(client: OryAgentClient, options: UserLoginOptions): Promise; /** Re-export so callers don't need to import auth.ts directly. */ export type { OryOAuth2Tokens }; /** * @deprecated Renamed to `ensureUserAuthenticated`. The old name will be * removed in a future release. The behaviour is unchanged. */ export declare const ensureAuthenticated: typeof ensureUserAuthenticated;