import { type AithosSessionStore } from "./session-store.js"; import { type AithosKeyStore } from "./key-store.js"; import { DelegateActor } from "./internal/delegate-state.js"; import { type SignedEnvelope } from "./internal/envelope.js"; import { OwnerSigners } from "./internal/owner-signers.js"; import { type DataClient, type AithosSchemaLite } from "./data.js"; /** Default URL of the Aithos auth backend. */ export declare const DEFAULT_AUTH_BASE_URL = "https://auth.aithos.be"; /** Dev-account auth backend (full prod parity: custodial + magic-link SES + * SSO). Pair it with `DEV_SDK_ENDPOINTS`: * `new AithosAuth({ authBaseUrl: DEV_AUTH_BASE_URL, apiBaseUrl: DEV_SDK_ENDPOINTS.api })`. */ export declare const DEV_AUTH_BASE_URL = "https://auth.dev.aithos.be"; /** Default URL of the Aithos primitives API (publish_identity, publish_ethos_edition, etc.). */ export declare const DEFAULT_API_BASE_URL = "https://api.aithos.be"; export interface AithosAuthConfig { readonly authBaseUrl?: string; /** * Base URL of the Aithos primitives API (`api.aithos.be`). Used by * {@link AithosAuth.signUp} to bootstrap the user's Ethos via * `aithos.publish_identity` after the auth account is created. Override * for staging or self-hosted deployments. Defaults to * {@link DEFAULT_API_BASE_URL}. */ readonly apiBaseUrl?: string; readonly fetch?: typeof fetch; readonly window?: Pick; /** Pluggable JWT-session storage. Defaults to {@link defaultSessionStore}. */ readonly sessionStore?: AithosSessionStore; /** Pluggable key persistence. Defaults to {@link defaultKeyStore}. */ readonly keyStore?: AithosKeyStore; /** * Public client key issued by Aithos for browser callers * (`pk__<…>`). When set, the custodial endpoints (`signUpCustodial`, * `verifyEmail`, `resendVerificationEmail`) authenticate as this app * by default — the caller no longer has to repeat the key on every * call. The corresponding `allowed_origins` allowlist must include the * current page's origin. * * Safe to ship in the browser bundle: it grants nothing beyond what * a visitor of the app can already do, is gated by Origin on every * call, and is rate-limited per IP by the backend. * * If your app authenticates with a SECRET Bearer API key from a * backend instead, leave this unset and pass `apiKey` per call. */ readonly publicKey?: string; } /** * Active Aithos session. Returned by JWT-backed entry points * (`signIn`, `signUp`, `handleCallback`). Recovery-file and mandate * sign-ins do NOT return an `AithosSession` — they yield the lighter * {@link OwnerInfo} / {@link DelegateInfo}. */ export interface AithosSession { readonly session: string; readonly exp: number; readonly did: string; readonly handle: string; readonly blob_b64: string; readonly blob_nonce_b64: string; readonly blob_version: number; readonly enc_key_b64: string; readonly is_first_login: boolean; } /** * Public information about the loaded owner identity. Available after * any owner-side sign-in (password, Google, recovery), regardless of * whether a JWT is also present. */ export interface OwnerInfo { readonly did: string; readonly handle: string; readonly displayName: string; } /** * Public information about a delegate session held by the SDK. Returned * by `importMandate` and `getDelegates`. */ export interface DelegateInfo { readonly mandateId: string; readonly subjectDid: string; readonly granteeId: string; readonly scopes: readonly string[]; /** ISO-8601, or null when the mandate has no `not_after`. */ readonly expiresAt: string | null; readonly label?: string; } export interface SignInWithGoogleOptions { /** * Opaque state the consumer app wants to recover after the OAuth * round-trip (e.g. a deep-link to resume on). Echoed back as * `?app_state=` on the final redirect. */ readonly appState?: string; /** * App id registered in the Aithos `aithos-auth-apps` table. When set * together with {@link returnTo}, the auth backend redirects the * browser to {@link returnTo} (post Google + Aithos sign-in) instead * of the legacy hard-coded `app.aithos.be/auth/callback`. * * The pair is required together: the backend rejects half-presence * with `sso_app_redirect_pair_required`. Use it for any consumer app * other than the canonical `app.aithos.be` (typically your own * domain in prod, `http://localhost:/auth/callback` in dev). */ readonly appId?: string; /** * Where the auth backend should 302 the browser back to after a * successful Google sign-in. MUST be on the app's * `allowed_redirect_uris` allowlist (registered with Aithos out of * band; see {@link appId}). Exact-match — wildcards rejected. */ readonly returnTo?: string; } export interface SignInInput { readonly email: string; readonly password: string; } export interface SignUpInput { readonly email: string; readonly password: string; readonly handle: string; readonly displayName?: string; } export interface SignUpResult { readonly session: AithosSession; readonly recoveryFile: Blob; readonly recoveryFilename: string; } /** * Input to {@link AithosAuth.completeSsoFirstLogin}. The handle is * required (the auth backend pre-generated one from the user's email * local-part, available on the session payload — we re-confirm it * here so the user can edit before commit). */ export interface CompleteSsoFirstLoginInput { readonly handle: string; readonly displayName?: string; } /** * Result of {@link AithosAuth.completeSsoFirstLogin}. Returns a recovery * file just like signUp — even though the user authenticated via Google, * the freshly-generated Ed25519 seeds are the only material that can * sign Aithos artifacts; without the recovery file, losing access to * the Google account means losing the ethos forever. */ export interface CompleteSsoFirstLoginResult { readonly session: AithosSession; readonly recoveryFile: Blob; readonly recoveryFilename: string; } export interface SignInWithRecoveryInput { /** Recovery file as a Blob (browser File input) or already-decoded JSON string. */ readonly file: Blob | string; } export interface ImportMandateInput { /** Delegate bundle as a Blob or already-decoded JSON string. */ readonly bundle: Blob | string; } /** * Input to {@link AithosAuth.inviteCustodial}. Sends an invitation magic link * that carries an opaque payload (typically a delegate bundle) to deliver to * the invitee on accept. Mandate-agnostic: `mandateBundle` may be ANY mandate * (read/write/append/ethos/compute…) — the auth backend stores it verbatim, * bound to a single-use token, and never parses it. * * The app authenticates via `apiKey` (server-only secret) or `publicKey` * (browser-safe, Origin-gated), or the constructor's default `publicKey`. * No user password here — the invitee chooses it when they accept. */ export interface InviteCustodialInput { readonly apiKey?: string; readonly publicKey?: string; /** Invitee email — receives the magic link. */ readonly email: string; /** * The mandate to deliver. Accept the SDK's `MintedMandate.bundle` (Blob), * a JSON string, or a plain bundle object — all normalized to a JSON string. */ readonly mandateBundle: Blob | string | Record; /** Token TTL in seconds (backend clamps to its policy). */ readonly ttlSeconds?: number; /** Optional display name pre-filled on the pending account. */ readonly displayName?: string; } /** Result of {@link AithosAuth.inviteCustodial}. */ export interface InviteCustodialResult { readonly status: "invited"; readonly email: string; readonly mailSent: boolean; readonly mailMessageId?: string; } /** * Input to {@link AithosAuth.acceptInvite}. `email` and `token` come from the * `?email=&token=` query string of the invitation link. `password` is set by * the invitee for a NEW account, or used to authenticate an EXISTING one — so * it's required whenever the user isn't already signed in. */ export interface AcceptInviteInput { readonly email: string; readonly token: string; readonly password?: string; } /** * Result of {@link AithosAuth.acceptInvite}. The token is consumed, the * session is hydrated (account created or existing one signed in), and the * invited mandate has been imported into the keystore — `delegate` describes * it. Read `delegate.subjectDid` to identify the issuer (e.g. resolve their * public Ethos via `sdk.ethos.of(delegate.subjectDid)`). */ export interface AcceptInviteResult { readonly status: "signed_in"; readonly session: AithosSession; readonly delegate: DelegateInfo; /** True when a new account was provisioned; false when an existing one signed in. */ readonly accountCreated: boolean; } /** * Input to {@link AithosAuth.signUpCustodial}. * * The caller authenticates as an app via ONE of: * - `apiKey` : server-only secret Bearer. Pass from your backend * only — never ship it in browser code. * - `publicKey` : browser-safe public client key. Safe to embed in * the bundle; the backend gates it by Origin and * rate-limits by IP. * * If you set `publicKey` on the {@link AithosAuth} constructor, omit * both fields here — the default credential is used. * * The `password` is always required and is chosen by the user (sign-up * no longer auto-generates one). The created account starts as * **pending** (`email_verified=false`); the user must click the * confirmation link sent by SES before {@link signInCustodial} works. */ export interface CustodialSignUpInput { /** Server-only Bearer secret. Mutually exclusive with `publicKey`. */ readonly apiKey?: string; /** Browser-safe public client key. Mutually exclusive with `apiKey`. * Overrides the constructor's default `publicKey` when provided. */ readonly publicKey?: string; /** Email address of the new user. Will receive the verification mail. */ readonly email: string; /** Raw password the user chose. ≥ 10 chars, mix of letters with * ≥ 1 digit or symbol. Enforced server-side. */ readonly password: string; /** Optional display name. Capped at 200 chars by the backend. */ readonly displayName?: string; /** Optional handle hint. Backend may sanitise or replace. */ readonly handleHint?: string; } /** * Result of {@link AithosAuth.signUpCustodial}. Always carries * `status: "pending_verification"` — the user must click the link in * their inbox before sign-in works. If `mailSent` is false the row * exists in DDB anyway; trigger {@link AithosAuth.resendVerificationEmail} * to retry the SES send. */ export interface CustodialSignUpResult { readonly status: "pending_verification"; readonly email: string; readonly mailSent: boolean; readonly mailMessageId?: string; } /** Input to {@link AithosAuth.verifyEmail}. Both fields come straight * out of the `?email=&token=` query string of the confirmation URL. */ export interface VerifyEmailInput { readonly email: string; readonly token: string; } /** * Result of {@link AithosAuth.verifyEmail}. Discriminated by `status`. * * - `"signed_in"` (magic-link mode): the user has been authenticated * in this call. A JWT session is persisted to the session store and * the local keystore is hydrated with the unwrapped seed bundle. * The caller can navigate the user straight to a logged-in area. * - `"already_verified"`: the verification link had already been * consumed on a previous click. No session is minted (the token is * spent). The caller should route the user to the sign-in form. */ export type VerifyEmailResult = { readonly status: "signed_in"; readonly session: AithosSession; readonly passwordMustChange: false; } | { readonly status: "already_verified"; readonly email: string; }; /** Input to {@link AithosAuth.resendVerificationEmail}. The `email` is * required; credential overrides follow the same rules as * {@link CustodialSignUpInput}. */ export interface ResendVerificationInput { readonly email: string; readonly apiKey?: string; readonly publicKey?: string; } export interface CustodialSignInInput { readonly email: string; readonly password: string; } /** * Active custodial session. Same JWT-backed shape as {@link AithosSession} * but adds a `passwordMustChange` flag the UI can honour to nudge the * user toward a `requestPasswordReset` on first login. */ export interface CustodialSignInResult { readonly session: AithosSession; readonly passwordMustChange: boolean; } export interface RequestPasswordResetInput { readonly email: string; } /** * Input to {@link AithosAuth.applyPasswordReset}. Finalises a password * reset started by {@link AithosAuth.requestPasswordReset}. The `email` * and `token` come straight from the magic-link URL that landed in the * user's inbox (`?email=…&token=…`); the `newPassword` is what the user * just typed in the reset page. */ export interface ApplyPasswordResetInput { /** Email address whose password is being reset. */ readonly email: string; /** Raw reset token extracted from the magic-link URL query string. */ readonly token: string; /** New password — must satisfy the backend's policy (≥ 10 chars). */ readonly newPassword: string; } /** * Result of {@link AithosAuth.applyPasswordReset}. Carries a fresh JWT * session so the UI can either redirect to a "you're now signed in" * landing or prompt the user to sign in explicitly with their new * credentials — same {@link CustodialSignInResult} shape as a normal * sign-in. * * Note: unlike {@link signInCustodial}, this DOES NOT hydrate the local * keystore. The reset path on the auth Lambda re-wraps the seed bundle * with KMS but doesn't return it (the user just typed a password — they * still need to sign in once to materialise the seeds locally). The * {@link AithosSession} returned here lets the app store the JWT and * call {@link signInCustodial} to complete hydration. */ export interface ApplyPasswordResetResult { readonly session: AithosSession; } export declare class AithosAuth { #private; readonly authBaseUrl: string; readonly apiBaseUrl: string; constructor(config?: AithosAuthConfig); /** * Reload signing material and JWT session from the configured stores. * Must be called once at app boot before relying on * {@link getCurrentSession} / {@link getOwnerInfo} / {@link canSignAsOwner} * — until then they reflect only what's been done in-memory in the * current tab. * * Strict consistency: if the JWT and the stored owner disagree about * who's signed in, both are wiped and the user re-auths. JWT-less * owner state (loaded from keyStore but no JWT) is a valid resumed * state — the user signed in via recovery or imported a mandate at * some earlier moment and never went through the JWT flow. */ resume(): Promise; /** JWT-backed session. Null when signed in via recovery / mandate / not at all. */ getCurrentSession(): AithosSession | null; /** Loaded owner identity. Independent of JWT presence. */ getOwnerInfo(): OwnerInfo | null; getDelegates(): readonly DelegateInfo[]; canSignAsOwner(): boolean; /** * Sign an envelope (spec §11.2) as the active owner, to authenticate * a call to a third-party Aithos-aware backend. * * Same primitive that SDK namespaces (`sdk.data`, `sdk.ethos`, * `sdk.mandates`, ...) use internally to sign their own writes to * `api.aithos.be`. Exposed here so apps can sign envelopes for their * own backends — any service that verifies a `SignedEnvelope` per * spec §11.2 (typically using `@aithos/protocol-core/envelope`'s * `verifyEnvelope`) accepts the resulting object. * * The envelope binds the signature to `(iss, aud, method, * params_hash, nonce, iat, exp)`, so it cannot be replayed against a * different endpoint, method, or payload, and expires after * `ttlSeconds` (default 60s, server-side typically caps at 300s). * * Usage: * * ```ts * const envelope = await sdk.auth.signEnvelope({ * aud: "https://api.example.com/v1/widgets", * method: "myapp.widgets.create", * params: { name: "Widget #1" }, * }); * await fetch("https://api.example.com/v1/widgets", { * method: "POST", * headers: { "content-type": "application/json" }, * body: JSON.stringify({ ...payload, _envelope: envelope }), * }); * ``` * * @throws {AithosSDKError} `auth_not_signed_in` if no owner identity * is loaded (call `signIn` / `signUp` / `signInCustodial` first). * @throws {AithosSDKError} `auth_invalid_sphere` if `sphere` is not * one of `"root" | "public" | "circle" | "self"`. */ signEnvelope(args: { /** * Absolute URL of the target endpoint (scheme + host + path, no * query, no fragment). The receiving server rejects the envelope if * `aud` does not match the actual request URL. */ readonly aud: string; /** Fully-qualified JSON-RPC method name. */ readonly method: string; /** * Tool payload — what `params_hash` commits to. Will be * JCS-canonicalized (RFC 8785 subset) before hashing, so JS object * key order does not affect the result. */ readonly params: unknown; /** * Which of the owner's four sphere keys signs. Default: `"public"`, * which matches what SDK namespaces use for everyday writes. * Choose `"root"`, `"circle"`, or `"self"` only if the receiving * server specifically expects one of those (rare). */ readonly sphere?: "root" | "public" | "circle" | "self" | "data"; /** * Envelope lifetime in seconds. Default 60. Aithos servers cap * at 300; third-party servers may apply their own cap. */ readonly ttlSeconds?: number; }): Promise; /** * Sign a **delegate-path** envelope for an external endpoint, on behalf of * the subject named in an imported delegate mandate. Unlike * {@link signEnvelope} (owner-path, requires a signed-in owner), this signs * with a delegate key alone — no owner session needed — which is exactly * what a broker / agent host holding a custodied mandate bundle requires. * * Resolve the delegate by `mandateId` (preferred, unambiguous) or by * `subjectDid` (uses the registry's active-actor pick). The envelope's * `iss` is the subject DID; `proof.verificationMethod` is the delegate's * bare multibase (matching `mandate.grantee.pubkey`); the full SignedMandate * is attached so the receiving server verifies the delegation per §11.6. * * @throws {AithosSDKError} `auth_no_delegate` when no imported mandate * matches, or `auth_bad_args` when neither selector is provided. */ signEnvelopeAsDelegate(args: { /** Absolute URL of the target endpoint (no query, no fragment). */ readonly aud: string; /** Fully-qualified JSON-RPC method name. */ readonly method: string; /** Tool payload — what `params_hash` commits to. */ readonly params: unknown; /** Mandate id to sign under (preferred). */ readonly mandateId?: string; /** Subject DID to sign for, when the mandate id is not at hand. */ readonly subjectDid?: string; /** Envelope lifetime in seconds. Default 60. */ readonly ttlSeconds?: number; }): Promise; canSignAsDelegateFor(did: string): boolean; /** * Internal accessor used by sibling SDK namespaces (compute, wallet, * ethos) when they need to sign on behalf of the owner. Returns null * if no owner is loaded. * * @internal */ _getOwnerSigners(): OwnerSigners | null; /** * Ready-made owner data client bound to the signed-in account, signing + * sealing under the dedicated **`#data`** sphere (the protocol-intended owner * data key). This is the one-liner apps should use instead of hand-rolling * `createDataClient` with a raw seed — hand-rolling with `#root` is exactly * what left legacy collections sealed to the wrong key. * * const data = auth.ownerDataClient({ schemas: [myVendorLite] }); * await data.collection("notes").insert({ ... }); // owned under #data * * Throws when no owner is signed in, or when the account has no `#data` * sphere (legacy accounts created before #data, or imported from a 4-seed * recovery). Add one first with `rotateEthos` / the migration scripts, then * re-import the resulting recovery — the error message says so. * * @param args.pdsUrl PDS base URL. Defaults to the SDK default (pds.aithos.be). * @param args.schemas Vendor `AithosSchemaLite` definitions to register for * WRITES (reads auto-resolve published schemas from the PDS). */ ownerDataClient(args?: { readonly pdsUrl?: string; readonly schemas?: readonly AithosSchemaLite[]; }): DataClient; /** * Ready-made DELEGATE data client, bound to a mandate held in this session * (imported via `importMandate` / an accepted invite). Same record-CRUD * surface as the owner client, bounded by the mandate's scope — you never * pass a key, a sphere, or the mandate itself to the data calls. * * const db = auth.delegateDataClient(); // single active mandate * await db.collection("prospects").insert({ ... }); // needs data.prospects.write * * With several active mandates, pass `{ subjectDid }` or `{ mandateId }`. * Owner-only ops (createCollection, authorizeDelegate, …) throw -32042 — the * owner does those once, at onboarding. */ delegateDataClient(args?: { readonly subjectDid?: string; readonly mandateId?: string; readonly pdsUrl?: string; readonly schemas?: readonly AithosSchemaLite[]; }): DataClient; /** * Unified data accessor — the database for "however you connected": * - signed in as owner → your own collections under `#data`; * - acting under an imported mandate → the subject's collections (per scope). * * Identical CRUD surface either way; the developer never sees a sphere, a * key, or the mandate. The mode follows how you authenticated, not a flag on * the data calls. * * const db = auth.data; * await db.collection("prospects").insert({ ... }); * * Only ambiguous when you are BOTH signed in as owner AND holding mandates; * then call `ownerDataClient()` / `delegateDataClient({ … })` explicitly. */ get data(): DataClient; /** * Internal accessor — looks up an active delegate by mandate id. * @internal */ _getDelegateActor(mandateId: string): DelegateActor | undefined; /** * Internal accessor — finds the first active delegate whose subject * matches `did`. Used by `sdk.ethos.of(did)` when the user holds a * mandate for that subject. * @internal */ _findDelegateForSubject(did: string): DelegateActor | undefined; /** * Sign in with email + password, dispatching automatically between * the legacy zero-knowledge flow ({@link signIn}) and the custodial * flow ({@link signInCustodial}) based on which mode the account * was provisioned with. * * Use this in apps that want a single sign-in form for users who * may have been created under either mode (e.g. an app that's * migrating from zk to custodial — pre-existing users stay zk * forever, new ones go custodial, the SDK figures it out). * * Strategy: try {@link signInCustodial} first (the modern path). * If the backend reports `auth_invalid_credentials` — which it * uniformly returns for "wrong password", "unknown user", AND * "user exists but not in custodial mode" (anti-enum) — fall * back to {@link signIn} (zk). * * Other failure modes from the custodial path are NOT swallowed: * - `auth_email_not_verified` → propagate (user is custodial but * hasn't clicked the confirmation link yet; the app should * surface a "resend mail" CTA rather than retrying as zk, * which would also fail and mask the real cause) * - server / network errors → propagate (don't double the * incident by retrying through the other flow) * * Latency profile: * - Pure custodial (success or wrong pwd) : 1 round-trip * - Pure zk (any outcome) : 1 custodial probe + 2 zk * - Unknown email : same as zk worst case * * Anti-enum note: timing slightly leaks the mode (custodial path is * faster than zk). Acceptable for V1 — rate limiting + strong * passwords are the real defenses. A future strict-anti-enum mode * could race both paths in parallel and accept the 2x backend load. */ signInAuto(input: SignInInput): Promise; signIn(input: SignInInput): Promise; signUp(input: SignUpInput): Promise; /** * Sign in by uploading a recovery file. Hydrates the owner signers * locally — no JWT is obtained on this path because the recovery * file alone doesn't authenticate against the auth backend (no * password, no Google session). Apps that need compute/wallet * access should follow up with an email+password sign-in or with * Google SSO. * * The recovery file is ALWAYS the file produced by `signUp` (or the * equivalent one emitted by `protocol-client`'s `runOnboarding`). * Both shapes are accepted. */ signInWithRecovery(input: SignInWithRecoveryInput): Promise; /** * Import a delegate bundle (`.aithos-delegate.json`). Works in any * state: with no owner loaded (delegate-only session), or alongside * an existing owner (the user holds mandates for other people's * ethoses while also being an owner themselves). */ importMandate(input: ImportMandateInput): Promise; removeMandate(mandateId: string): Promise; signInWithGoogle(opts?: SignInWithGoogleOptions): never; /** * Public entrypoint — dedupes concurrent calls (React StrictMode). * The first call kicks off the actual exchange; subsequent calls * before that promise resolves return the SAME promise so they all * receive the same `AithosSession | null`. Otherwise StrictMode's * second invocation would race against the URL clean done by the * first call and resolve to `null`, robbing the AuthCallback page * of the session it actually obtained. */ handleCallback(): Promise; exchange(aithosCode: string): Promise; /** * Finish the first-time Google SSO bootstrap. After * `signInWithGoogle()` + `handleCallback()`, a brand-new SSO user has * a session JWT and an `enc_key` released by the auth backend, but * NO Aithos identity yet (no Ed25519 seeds, no published did.json, * no blob in the auth vault). This method closes that gap: * * 1. Generates a fresh {@link BrowserIdentity} client-side (4 * Ed25519 keypairs, derived DID). * 2. Calls `aithos.publish_identity` on api.aithos.be so reads * and writes against the Aithos primitives have an ethos to * anchor to. * 3. AES-GCM-encrypts the seeds with the session's `enc_key`, * PUTs the result to `/auth/blob`. From now on, every Google * sign-in for this user will receive the encrypted blob and * hydrate locally. * 4. Hydrates `ownerSigners` + `keyStore` so `canSignAsOwner()` * flips to true. * 5. Returns a recovery-file Blob — the only material that can * restore this ethos if Google access is lost. * * Preconditions: * - `getCurrentSession()` returns a non-null session (caller went * through `handleCallback()` already). * - The session's `blob_version` is 0 (i.e. no blob yet). * - The session's `enc_key_b64` is non-empty. * * Throws `AithosSDKError("auth_sso_no_pending_first_login", …)` if * preconditions don't hold (e.g. blob_version > 0 means the user has * already completed setup; nothing to do). */ completeSsoFirstLogin(input: CompleteSsoFirstLoginInput): Promise; /** * Provision a custodial-mode account on behalf of a registered app. * * Two integration patterns: * - **Frontend-only** apps : set `publicKey` on the constructor * (or on this call). Safe to ship in browser bundles — the * backend gates each request by Origin + IP rate limit. * - **Backend-fronted** apps : the backend passes `apiKey` (secret * Bearer); the browser never sees the credential. * * The created account is in a *pending* state — sign-in stays blocked * until the user clicks the confirmation link sent to their inbox. * Call {@link verifyEmail} from the page mounted on * `app.verify_base_url` to consume the token; afterwards * {@link signInCustodial} works. * * Errors map to `AithosSDKError` codes: * - `auth_missing_api_key` (no credential provided) * - `auth_invalid_api_key` (Bearer rejected by backend) * - `auth_invalid_public_key` (public key rejected by backend) * - `auth_api_key_revoked` / `auth_public_key_revoked` * - `auth_origin_not_allowed` (public key + Origin not in allowlist) * - `auth_password_too_weak` (400 — server-side strength check) * - `auth_email_exists` (409 — email already registered) * - `auth_email_invalid` (400 — bad email format) * - `auth_mail_send_failed` (502 — DDB row exists but SES failed) * - `auth_custodial_signup_failed` (catch-all) */ signUpCustodial(input: CustodialSignUpInput): Promise; /** * Magic-link auto-signin: consume the verification token from the * confirmation link, KMS-unwrap the seed bundle server-side, and * hydrate the local session + keystore in one round-trip. * * Outcome depends on the link's state: * - First click on a fresh link → returns * `{ status: "signed_in", session, … }`. The session store is * populated, the owner signers are loaded — the user is signed * in. The caller should navigate them to a logged-in route. * - Click of an already-consumed link → returns * `{ status: "already_verified", email }`. No session is minted; * the user must sign in via {@link signInCustodial}. * * Mount this on the page declared as `verify_base_url` in your app's * registration. Read `email` + `token` from `window.location.search`, * call this, branch on `result.status`. * * Throws `auth_token_invalid_or_expired` if the token is wrong or * past its 1h TTL — surface a "request a fresh link" CTA in that case. */ verifyEmail(input: VerifyEmailInput): Promise; /** * Send an invitation magic link carrying a mandate. The issuer (owner) * mints any mandate via {@link AithosSDK.mandates} (read/write/append/…), * then calls this with the bundle: the auth backend stores it bound to a * single-use token and emails the magic link. The mandate (and its delegate * seed) never ride the email URL. The invitee redeems it via * {@link acceptInvite}. * * Generic — knows nothing about the mandate's scope. Authenticate with * `apiKey` (server) or `publicKey` (browser, Origin-gated). */ inviteCustodial(input: InviteCustodialInput): Promise; /** * Redeem an invitation from the magic link: consume the token, sign in * (create the account with `password`, or authenticate an existing one), * and AUTO-IMPORT the mandate the inviter attached. Returns the session and * the imported {@link DelegateInfo}. * * Mount this on the page declared as the invitation's verify/redirect URL; * read `email` + `token` from `window.location.search`, collect the * `password`, call this. * * Throws `auth_token_invalid_or_expired` (bad/consumed/expired token) or an * auth error if an existing account's password is wrong / a new one is weak. */ acceptInvite(input: AcceptInviteInput): Promise; /** * Re-send the verification mail for a pending account. Use when the * user reports never having received the welcome mail, or when their * verification token expired (24h TTL). * * The backend is anti-enumeration (always 200) and rate-limited * 1/h/account, so it's safe to call even when the state of `email` * is unknown. Accepts the same credential families as * {@link signUpCustodial}; falls back to the constructor's * `publicKey` when neither override is set. */ resendVerificationEmail(input: ResendVerificationInput): Promise; /** * Authenticate a custodial-mode user with email + password. Single * round-trip: returns a fresh JWT session AND hydrates the local * KeyStore with the user's 4 Ed25519 seeds (KMS-unwrapped server-side * after Argon2id verify). * * After this returns, the SDK is ready to publish ethos editions, * invoke compute, mint mandates, etc. — exactly as if the user had * signed in via {@link signIn} (zk) or {@link handleCallback} (SSO). * * Errors map to `AithosSDKError` codes: * - `auth_invalid_input` (your code passed empty fields) * - `auth_invalid_credentials` (401 — wrong email / wrong password) * - `auth_wrong_auth_mode` (403 — user exists in another flow) */ signInCustodial(input: CustodialSignInInput): Promise; /** * Trigger a password-reset email to the given address. Backend ALWAYS * resolves silently (no enumeration) — caller cannot tell whether the * email is registered or not. The mail itself, if sent, contains a * magic-link URL of shape `?token=&email=`. * * Per-email rate limits apply server-side (5 mails/day, 5 min cooldown * between consecutive requests). Calls during cooldown silently no-op * the mail send while still returning success here. */ requestPasswordReset(input: RequestPasswordResetInput): Promise; /** * Finalise a password reset using the magic-link token sent to the * user's inbox by {@link requestPasswordReset}. * * Typical use site: the page mounted on the reset URL declared in * `aithos-auth-apps.reset_base_url`. The page reads `email` and * `token` from `window.location.search`, prompts the user for a new * password, then calls this method. * * On success, the returned {@link AithosSession} is persisted to the * session store but the local keystore is NOT hydrated — the backend * does not return the seed bundle on this endpoint. To get a fully * usable session (one that can sign envelopes), follow up with * {@link signInCustodial} using the email + new password. The two * round-trips can be hidden inside a single UI action: reset → auto * sign-in → redirect to dashboard. * * Errors map to `AithosSDKError` codes: * - `auth_invalid_input` (your code passed empty fields) * - `auth_reset_token_invalid` (400 — token forged / wrong email) * - `auth_reset_token_expired` (410 — token TTL elapsed) * - `auth_reset_token_consumed` (409 — already used) * - `auth_password_too_short` (400 — < 10 chars) * - `auth_custodial_reset_failed` (catch-all) */ applyPasswordReset(input: ApplyPasswordResetInput): Promise; signOut(): Promise; /** * Ensure the signed-in owner's PUBLISHED `did.json` carries the dedicated * `#data` verification method, additively re-publishing it (via the * idempotent `aithos.augment_identity` primitive) when it's missing. * * Why this exists: owner data/asset PDS envelopes are signed under the * `#data` sphere (`auth.ownerDataClient` / `sdk.data`). The PDS resolves the * issuer DID document from the registry's published `did.json`; if that copy * predates the `#data` sphere (account created before it landed, or published * by an older client), the resolver falls back to a root-only synthesis that * exposes only `#root/#public/#circle/#self`. Every `#data`-signed write then * fails with `-32011 proof.verificationMethod #data not found in issuer * DID document`. A plain `publish_identity` republish can't fix it (the server * rejects a "different did.json"); the additive `augment_identity` can. * * New accounts already publish `#data` at sign-up, so this is a no-op for * them. Idempotent and cached per session. Call after sign-in if you want to * guarantee the PDS can resolve your `#data` key before the first write — * though the SDK now also runs it automatically on `resume` and the * existing-account sign-in flows. * * @throws AithosSDKError `auth_not_signed_in` when no owner is loaded, * `auth_no_data_sphere` when the owner has no `#data` seed, or * `data_sphere_publish_failed` when the (re-)publish fails. */ ensureOwnerDataPublished(): Promise; } //# sourceMappingURL=auth.d.ts.map