Client libraries
WIPVanilla authCreateClient + React AuthProvider + hooks. Vue, Svelte, and Solid clients are also shipped.
What the clients give you
The duck-auth client libraries wrap the JSON sign-in / sign-out / session routes so your UI doesn't have to know the wire shape. They:
- Track session state with
loading/authed/guestsemantics. - Provide a
signIn(providerId, input)that handles the right HTTP method and surfaces typed errors. - Re-render reactive views (React
authUseSession, VueauthUseSession, Svelte stores, Solid signals) when the session changes. - Subscribe to
session.rotated/session.revokedso a sign-out in one tab signs you out in every tab.
Shipped clients
| Client | Import | Notes |
|---|---|---|
| Vanilla | @gentleduck/auth/client/vanilla | Framework-agnostic. Zero dependencies. |
| React | @gentleduck/auth/client/react | <AuthProvider> + authUseSession + authUseSignIn + authUseBeginProvider. |
| Vue | @gentleduck/auth/client/vue | createAuth() + authUseSession. |
| Svelte | @gentleduck/auth/client/svelte | authCreateStore() reactive store. |
| Solid | @gentleduck/auth/client/solid | createAuthSignal(). |
Anatomy of a sign-in
Every client wraps the same HTTP shape:
POST /auth/signin
Content-Type: application/json
{ "providerId": "password", "input": { "email": "...", "password": "..." } }
The server responds with:
HTTP/1.1 200 OK
Set-Cookie: __Host-duck-sid=...; ...
Content-Type: application/json
{ "session": {...}, "identity": {...} }
The client persists the response, kicks off a getSession() refresh,
and notifies subscribers.
Type safety
Every client is generic over Profile:
type Profile = { displayName: string; avatarUrl?: string }
// Vanilla
const client = authCreateClient<Profile>()
// React - pass through authUseSession's generic
const { data } = authUseSession<Profile>()
// data.identity.profile is typed as Profile
For a fully end-to-end type-safe stack, share the Profile type
between your AuthEngine config (server) and your client setup (browser)
through your monorepo's shared types package.
Cross-tab session sync
The clients listen for storage events on localStorage (vanilla / React)
and BroadcastChannel messages (Vue / Svelte / Solid) so that a
sign-out in one tab propagates to every open tab in the same browser.
The mechanism is opt-in but on by default - pass notifyImmediately: false if you don't want it.
Error handling
All clients raise the typed AuthError (or a wire-equivalent
{ code, status, meta } object on the React authUseSignIn().error field).
Branch on error.code, not on HTTP status - codes are stable across
versions.
const signIn = authUseSignIn()
await signIn.mutateAsync({ providerId: 'password', input: { email, password } })
if (signIn.error) {
switch (signIn.error.code) {
case 'AUTH/INVALID_CREDENTIALS': toast('Wrong email or password'); break
case 'AUTH/MFA_REQUIRED': showMfaForm(); break
case 'AUTH/RATE_LIMITED': toast('Slow down - try again in a minute'); break
}
}