AuthDanceClient owns the current credentials. Each flow returns an AuthDanceClientChoreography, a small state machine that tells the UI what to ask next.
The answer loop
const client = new AuthDanceClient({ baseUrl: "/api/auth" });
using dance = await client.signIn();
while (!dance.done) {
if (dance.prompt?.kind === "choice") {
await dance.choose(await chooseBranch(dance.choices));
continue;
}
if (dance.current?.sendable) await dance.sendPrompt();
await dance.submitPrompt(await readValue(dance.current!));
}
Read dance.current for one input. Read dance.choices when the prompt branches. dance.trail lists the component names already answered.
All nine flows
| Flow | Call | Argument |
|---|---|---|
| Sign in | client.signIn() |
none |
| Sign up | client.signUp() |
none |
| Recover | client.recover("password") |
component |
| Enroll | client.enroll("totp") |
component |
| Unenroll | client.unenroll("totp") |
component |
| Rotate | client.rotate("password") |
component |
| Subscribe | client.subscribe("sms") |
channel |
| Unsubscribe | client.unsubscribe("sms") |
channel |
| Delete | client.delete() |
none |
Enrollment, unenrollment, rotation, subscription, unsubscription, and deletion require an authenticated session and a recent sign-in.
Persist an unfinished dance
Pass a choreography store so a page can resume after a reload. webStorageStore adapts browser storage.
import { webStorageStore } from "auth-dance/client";
using dance = await client.signIn({
store: webStorageStore("auth-dance:sign-in", localStorage),
});
Use prev() to go back one step, restart() to begin again, and abandon() to discard local flow state. These actions do not alter a completed identity by themselves.
Handle confirmations and errors
Unenroll, unsubscribe, and delete finish with a confirmation prompt. Call dance.confirm() after the UI receives the user's explicit confirmation. Route errors are mapped to the exported Auth Dance error classes; client-side state mistakes use AuthDanceClientError subclasses.