UNPKG

accounts

Version:

Tempo Accounts SDK

180 lines 8.42 kB
import { Hex } from 'ox'; import type { Address, Transport } from 'viem'; import * as z from 'zod/mini'; import { type Handler, from } from '../../Handler.js'; import * as Kv from '../../Kv.js'; import * as Session from './session.js'; /** * Session payload persisted in the session store and surfaced via * `getSession`. `address` is the account address that signed the * authentication challenge; `chainId` is the chain echoed in the message. */ export type SessionPayload = { /** Address of the account. */ address: Address; /** Chain ID echoed into the challenge message. */ chainId: number; /** Unix timestamp (seconds) when the session was issued. */ issuedAt: number; /** Unix timestamp (seconds) when the session expires. */ expiresAt: number; }; /** Zod schemas for the auth handler's request and response payloads. */ export declare namespace schema { /** Schemas for `POST {path}/challenge`. */ namespace challenge { /** Request body schema. */ const parameters: z.ZodMiniObject<{ chainId: z.ZodMiniOptional<z.ZodMiniNumber<number>>; }, z.core.$strip>; /** Response body schema. */ const returns: z.ZodMiniObject<{ message: z.ZodMiniString<string>; }, z.core.$strip>; } /** Schemas for `POST {path}` (verify). */ namespace verify { /** Request body schema. */ const parameters: z.ZodMiniObject<{ address: z.ZodMiniTemplateLiteral<`0x${string}`>; message: z.ZodMiniString<string>; signature: z.ZodMiniTemplateLiteral<`0x${string}`>; /** * When `true`, the server returns the issued session token in the * response body as `{ token }` and does NOT set a session cookie. * The caller is responsible for sending it as * `Authorization: Bearer <token>` on subsequent requests. */ returnToken: z.ZodMiniOptional<z.ZodMiniBoolean<boolean>>; }, z.core.$strip>; /** Response body schema. */ const returns: z.ZodMiniObject<{ token: z.ZodMiniOptional<z.ZodMiniString<string>>; }, z.core.$strip>; } } /** * Server Authentication request handler. Mounts three routes under `path`: * * - `POST {path}/challenge` → `{ message }` * - `POST {path}` → verify and issue a session (cookie via `Set-Cookie`) * - `POST {path}/logout` → clear the session cookie * * The returned handler also exposes `getSession(req)` for resolving the * current session from a follow-up request's cookie. * * The challenge message is wire-formatted as EIP-4361 (SIWE) for ecosystem * compatibility, but address binding is deferred: the SDK can fold the * challenge digest into the connect ceremony before the account knows * which address it will sign with. The wallet supplies the real address at * verify time and the server uses it as the session subject. */ export declare function auth(options?: auth.Options): auth.ReturnType; export declare namespace auth { /** Return type of `auth()` — a `Handler` extended with `getSession`. */ type ReturnType = Handler & { getSession: getSession; }; /** Resolves the current session from a request's cookie or bearer token. */ type getSession = (req: Session.SessionRequest) => Promise<SessionPayload | undefined>; /** * Hook invoked after a SIWE signature is verified but before the * session token is issued. Returning a `Response` merges its JSON * body and status onto the verify response. Throwing rejects with * `401` — the thrown error's `message` is surfaced as the response * `error` field — and no session is issued. */ type onAuthenticate = (params: { /** Verified address that signed the SIWE message. */ address: Address; /** Chain ID parsed from the SIWE message. */ chainId: number; /** Verbatim SIWE message that was signed. */ message: string; /** Underlying request — useful for headers, IP, etc. */ request: Request; /** Signature provided by the wallet. */ signature: Hex.Hex; }) => Response | Promise<Response> | void | Promise<void>; type Options = from.Options & { /** * Whether to issue a session cookie on successful verify. When * `false`, the verify response always contains `{ token }` in the * body (the per-request `returnToken` flag is ignored), no * `Set-Cookie` header is sent, logout does not clear a cookie, and * `getSession` ignores any incoming cookie — only * `Authorization: Bearer <token>` is honored. Use this when the SDK * lives in a non-browser context (CLI, server-to-server) or when * the host app already manages auth cookies. * @default true */ cookie?: boolean | undefined; /** Cookie name for the session token. @default "accounts_auth" */ cookieName?: string | undefined; /** Domain echoed into challenge messages. @default request `Host` header */ domain?: string | undefined; /** * Hook invoked after the SIWE signature is verified but before the * session token is issued. Use to provision a user record, emit * analytics, or apply application-level allow/deny rules. Throwing * from this hook rejects the request with `401` and the thrown * error's `message` is surfaced as the response `error` field. */ onAuthenticate?: onAuthenticate | undefined; /** Path prefix for the auth endpoints. @default "/" */ path?: string | undefined; /** * Pinned canonical public origin (e.g. `'https://app.example.com'`). * When set, the SIWE `domain` and `uri`, and the cookie `Secure` flag, * are derived from this URL — request `Host`, request URL, and * `x-forwarded-*` headers are ignored. This is the recommended setting * for production deployments behind a CDN or reverse proxy: it * prevents a spoofed `x-forwarded-host` from shifting the SIWE domain * and a spoofed `x-forwarded-proto: http` from disabling `Secure`. */ origin?: string | undefined; /** * Whether to issue a session on successful verify. When `false`, * verify acts as a stateless signature check — no token is generated, * no entry is written to the session store, and no cookie is sent. * The verify response is `{}`. `getSession` always returns * `undefined` and `/logout` is a no-op (still returns `204`). Use * this when the host application mints its own session token (e.g. * a JWT inside `onAuthenticate`). * @default true */ session?: boolean | undefined; /** * Backing store for both single-use challenges (nonces) and issued * sessions. Keys are namespaced internally (`challenge:…`, `session:…`). * @default `Kv.memory()` */ store?: Kv.Kv | undefined; /** * Viem transport for the Tempo client used to verify signatures. The * client is always built against the `tempo` chain — Tempo's * `chain.verifyHash` natively understands `SignatureEnvelope` and * falls back to ECDSA recovery for plain EOAs. * @default `http()` */ transport?: Transport | undefined; /** * Honor `x-forwarded-proto` / `x-forwarded-host` to derive the public * origin. Required when running behind a trusted reverse proxy that * terminates TLS (OrbStack on `*.tempo.local`, a CDN, etc.). When * `false`, forwarded headers are ignored to prevent spoofing on * deployments that expose the origin server directly. Ignored when * `origin` is set. * @default `true` on Cloudflare Workers (always edge-fronted), `false` elsewhere. */ trustProxy?: boolean | undefined; /** TTLs in seconds. */ ttl?: { /** Challenge (nonce) TTL. @default 600 (10m) */ challenge?: number | undefined; /** Session TTL. @default 86400 (24h) */ session?: number | undefined; } | undefined; }; } //# sourceMappingURL=auth.d.ts.map