import type { IncomingMessage, ServerResponse } from "node:http"; /** * Cookie-handoff session for the Cortex Cloud control surface. * * Flow: * 1. User clicks "Open Cortex" in pyre-web. * 2. Pyre-web mints a short-lived signed token (HMAC-SHA256 with the * per-deployment gateway secret) carrying { sub: userId, * tenant: tenantId, exp: now+5min }. * 3. Pyre-web links to `https:///cortex-session/issue?token=`. * 4. This module's `handleIssue` verifies the token, sets a * `__Host-cortex-session` cookie (Secure, HttpOnly, SameSite=Strict) * with a longer expiry (e.g. 24h), then 302s to `/`. * 5. Subsequent requests carry the cookie. `verifyCookie()` checks * the signature against the gateway secret and accepts or rejects. * * The cookie value is itself a signed token (same HMAC, longer expiry) * so the server doesn't need session storage. Stateless. * * Why not a full JWT lib: this is a single-key HMAC use case in * a single trust boundary. Pulling jose / jsonwebtoken in adds 100KB * for one function. The Node `crypto` builtins do it in ~40 lines. * * Signing key resolution: `process.env.PRZM_CORTEX_GATEWAY_SECRET`. Must be * present for the cookie session to be enabled. */ declare const COOKIE_NAME = "__Host-cortex-session"; declare const ISSUE_TOKEN_TTL_SEC: number; declare const SESSION_COOKIE_TTL_SEC: number; export interface SessionClaims { /** User id (numeric). Source: pyre-web's Users collection. */ sub: number; /** Tenant id (numeric). Source: pyre-web's Tenants collection. */ tenant: number; /** Issued-at, unix seconds. */ iat: number; /** Expiry, unix seconds. */ exp: number; } /** * Sign a claims payload with HMAC-SHA256. Output is the compact form * `.` — JWT-ish but without * a header (single algorithm, no negotiation, no `alg: none` risk). */ export declare function signToken(claims: SessionClaims, key: string): string; /** * Verify a compact token. Returns the claims on success, `null` * otherwise (bad signature, malformed, expired). Constant-time on the * signature check. */ export type VerifyFailureReason = "malformed" | "bad-signature" | "expired" | "bad-payload"; export interface VerifyResult { ok: boolean; claims?: SessionClaims; reason?: VerifyFailureReason; } /** * Detailed verify — surfaces *why* a token failed so the issuer can * log it. The plain `verifyToken` wrapper preserves the original * "claims or null" contract for existing callers (cookie path). */ export declare function verifyTokenDetailed(token: string, key: string): VerifyResult; export declare function verifyToken(token: string, key: string): SessionClaims | null; /** * Extract the session cookie from a request. Returns the verified * claims when valid, `null` otherwise. Reads the signing key from * `PRZM_CORTEX_GATEWAY_SECRET`; when that env var is unset, cookie session * is disabled and this returns `null` for every request (callers fall * back to bearer / gateway-secret gates). */ export declare function verifyCookie(req: IncomingMessage): SessionClaims | null; /** * `/cortex-session/issue?token=` handler. Verifies the * issue token, mints a longer-lived session cookie, redirects to `/` * (or to `?next=` when provided and same-origin). * * Returns true when handled, false when the path doesn't match — the * caller falls through to its own routing. */ export declare function handleIssue(req: IncomingMessage, res: ServerResponse, logger?: { warn: (msg: string, extra?: Record) => void; }): Promise; /** TTL on issue tokens — used by pyre-web's link minter. */ export { ISSUE_TOKEN_TTL_SEC, SESSION_COOKIE_TTL_SEC, COOKIE_NAME }; //# sourceMappingURL=cookie-session.d.ts.map