Client SDK & Hooks
Primitives, not components. A framework-agnostic client (createAuthClient) over every endpoint plus thin React hooks (./react) — your forms, your styling, your decisions. HTMX is the special case (declarative server fragments); everything else gets the client + a hook / composable.
#createAuthClient
import { createAuthClient } from '@absolutejs/auth/client';
// Framework-agnostic SDK over every endpoint your auth() mounted. Every method
// returns { data, error } so you can branch without try/catch. Override routes
// if you mounted any of them at a custom path; pass a custom fetch for tests.
const client = createAuthClient({
baseUrl: '', // default: relative paths
credentials: 'same-origin', // default; sends the session cookie
routes: { login: '/api/v2/login' } // optional overrides
});
const { data, error } = await client.signIn.email({ email, password });
if (error) showError(error.message);
else if (data.status === 'mfa_required') openMfaPrompt();
else if (data.passwordCompromised) showResetBanner();
else go('/profile');
await client.passwordless.requestMagicLink({ email });
await client.mfa.challenge({ code });
const sessions = await client.sessions.list();#React hooks
The @absolutejs/auth/react sub-export ships thin hooks over the client: { isPending, data, error, mutate, reset } (mutations) or { isPending, data, error, refetch, revoke } (useSessions). React is an optional peer dependency — install it if you use the hooks. Vue composables, Solid signals, and Svelte stores will land as sibling sub-exports wrapping the same client.
import { createAuthClient } from '@absolutejs/auth/client';
import {
useMagicLink,
useMfaChallenge,
useSessions,
useSignIn
} from '@absolutejs/auth/react';
// React peer-dep is optional. The hooks are thin: { isPending, data, error,
// mutate, reset } over the client (or { isPending, data, error, refetch,
// revoke } for the sessions query). Bring your own form / styling.
const client = createAuthClient();
function SignInForm() {
const { mutate, isPending, error, data } = useSignIn(client);
return (
<form onSubmit={(e) => {
e.preventDefault();
const form = new FormData(e.currentTarget);
mutate({
email: form.get('email') as string,
password: form.get('password') as string
});
}}>
<input name="email" type="email" />
<input name="password" type="password" />
<button disabled={isPending}>Sign in</button>
{error && <p>{error.message}</p>}
{data?.status === 'mfa_required' && <MfaPrompt />}
</form>
);
}
// Vue / Solid / Svelte composables wrap the same client — same shapes,
// different reactivity. 0.33.0 shipped the sibling sub-exports:
// @absolutejs/auth/vue, @absolutejs/auth/solid, @absolutejs/auth/svelte.#Passkey autofill
0.37.0 ships usePasskeyAutofill across React, Vue, Solid, and Svelte.
@simplewebauthn/browser is an optional peer dep loaded via dynamic import; non-passkey consumers pay nothing.
import { createAuthClient } from '@absolutejs/auth/client';
import { usePasskeyAutofill } from '@absolutejs/auth/react';
// 0.37.0: WebAuthn conditional-UI. Mount on the sign-in page with an
// <input autocomplete="username webauthn"> and call start() in an effect;
// the browser surfaces the user's saved passkeys directly in its autofill
// dropdown — one tap and you're authenticated. @simplewebauthn/browser is
// an optional peer dep loaded dynamically; non-passkey consumers pay nothing.
const client = createAuthClient();
function SignInForm() {
const { start, data, error, isPending } = usePasskeyAutofill(client);
useEffect(() => { void start(); }, [start]);
return (
<form>
<input
name="email"
autoComplete="username webauthn"
/>
<input name="password" type="password" autoComplete="current-password" />
<button disabled={isPending}>Sign in</button>
{data?.status === 'authenticated' && <Redirect to="/dashboard" />}
{error && <p>{error.message}</p>}
</form>
);
}#Upgrade to passkey
useUpgradeToPasskey queries whether the signed-in user has any passkeys yet and exposes a shouldPrompt flag — true iff they have none. Wire it to a post-sign-in CTA so password users see a "save a passkey to this device?" prompt.
import { useUpgradeToPasskey } from '@absolutejs/auth/react';
// 0.37.0: "save a passkey to this device?" prompt for password users.
// shouldPrompt is true iff the signed-in user has zero passkeys; register()
// runs the WebAuthn registration ceremony and refetches the list.
function PostSignInPasskeyPrompt({ client }) {
const { shouldPrompt, register, isPending } = useUpgradeToPasskey(client);
if (!shouldPrompt) return null;
return (
<Banner>
Save a passkey to this device for faster sign-in next time?
<button onClick={() => register()} disabled={isPending}>
Save passkey
</button>
</Banner>
);
}