threshold1

Constructor & Config

Every option new Threshold1(...) accepts, generated directly from the installed package's own type declarations.

Generated directly from @threshold1/auth@0.3.0 — the real, currently-installed package, not hand-typed. Regenerated on every build; if this page and the actual SDK ever disagree, the SDK is right and this page needs a rebuild, not an edit.

Methods

Constructor

new Threshold1(config): Threshold1;

Parameters

config

Threshold1Config

Returns

Threshold1

Types

Threshold1Config

Properties

apiKey

apiKey: string;

Your Threshold1 API key (starts with th_live_). Issued from the Threshold1 developer dashboard.


auth?

optional auth?: AuthConfig;

Optional authentication orchestration settings for login().


baseUrl?

optional baseUrl?: string;

Override the default API base URL. Defaults to https://threshold1.phantomclick.in/api/v1 (the hosted production API) — no baseUrl needed for a normal integration. Set this to e.g. http://localhost:3000/api/v1 when developing against a local server.


debug?

optional debug?: boolean;

Enable debug logging for the login/register fallback chain.


redirectUrl?

optional redirectUrl?: string;

Optional URL to redirect back to after magic-link verification. The JWT and userId will be appended as query parameters.


AuthConfig

type AuthConfig = object;

Properties

fallback?

optional fallback?: FallbackMode;

Controls login()/register() cascade behavior and whether device recognition (State B) is engaged. See FallbackMode above. Defaults to "smart".


onAfterAuth?

optional onAfterAuth?: (user, method) => Promise<void> | void;

Called after any successful authentication (register or login). Receives the authenticated user and which method succeeded. Use to link the threshold1 user to your own database.

Fires consistently across every successful auth path: register(), login(), registerPasskey(), loginWithPasskey(), verifyOtp(), loginDiscoverable(), verifyDeviceCode(), verifyBackupCode(), and resumeSession() — whether called directly or through the register()/login() orchestrators.

Exception: registerWithMagic() / loginWithMagic() do NOT fire this — they only queue an email, there is no authenticated user yet. For magic-link flows this fires later, when the link is verified inside resumeSession() on the page the link redirects back to.

Exception: addPasskey(), enrollTotp(), verifyTotp(), sendSmsOtp(), verifySmsOtp(), and generateBackupCodes() do NOT fire this either — they attach or confirm a factor on an ALREADY-authenticated session (they all require requireToken()), so there's no new register/login event to report. verifyBackupCode() is the one exception among the Sprint 3 methods: unlike the others, it establishes a brand new session (account recovery when the primary factor is unavailable), so it fires this hook like any other login path.

Parameters

user

UserProfile

method

AuthMethod

Returns

Promise<void> | void

Example

onAfterAuth: async (user, method) => {
  await myDB.upsert({ email: user.email, t1UserId: user.id })
}

onFallback?

optional onFallback?: (attempted, usedMethod) => void;

Called when a method fails and SDK falls back to the next. Use to show UI feedback during fallback.

Parameters

attempted

string

usedMethod

string

Returns

void


FallbackMode

type FallbackMode = "manual" | "automatic" | "smart";

Controls how aggressively login()/register() move past a failed attempt, and whether the three-state device-recognition model (State A/B/C — see README) is engaged at all.

"manual" — Never auto-cascades. A failed passkey attempt (with an identifier) or a failed discoverable attempt (without one) is surfaced immediately (thrown) for the app to handle — call sendOtp()/loginWithMagic()/loginWithPasskey() etc. yourself. Device recognition is never consulted.

"automatic" — Auto-cascades through passkey → magic → otp when an identifier is known (same order the old auth.methods default used). Without an identifier, behaves like "manual" for the entry point itself (there's no identifier to cascade to) — device recognition is still never consulted, so a failed discoverable attempt always surfaces as "no identifier", never a one-tap confirm.

"smart" — (default) Same cascade as "automatic" when an identifier is known. Without one, a failed discoverable attempt triggers a device-recognition check: if this device is recognized and has a fallback method enrolled, login() resolves with { status: "confirm_required", ... } instead of throwing — call confirmDeviceSend() once the user taps confirm, then verifyDeviceCode(code). This is never silent: per the three-state model's hard rule, a recognized device still requires an explicit user tap before anything is sent.