Client SDK
@authoric/js: sign-in, data, realtime, files, teams and billing for your app's own users, from a browser, React Native or your server.
@authoric/js is the library your app's frontend calls Authoric with. It speaks for one of your
app's signed-in users (or nobody, for signing in), and wraps the same REST API documented in the
API reference: sign-in and the user's own account, your tables, live changes,
custom actions, files, organizations, roles and billing.
npm install @authoric/jsimport { createClient } from "@authoric/js";
const authoric = createClient({
url: "https://api.authoric.ai", // your API's address
appUid: "0199a3c2-…", // your app's uid, from its page in the console
});
const result = await authoric.auth.signInWithPassword({ email, password });
if (result.mfa) {
await authoric.auth.mfa.verify({ challengeId: result.mfa.challengeId, code });
}
const { items } = await authoric.from("invoices").list({ where: { status: "approved" }, limit: 25 });It runs anywhere fetch does: browsers, Node 18+, Deno, Bun, edge runtimes and React Native. It has
no dependencies of its own.
What it holds
createClient takes two things, the API's address and your app's uid, and neither is a secret. The
browser holds nothing else but the signed-in user's own session. Everything the user may do is
decided on the server: which rows they read and write, which organization a row belongs to, which
columns are redacted, which tables are locked. The client sends requests; the server decides.
Agent API keys (plak_…) belong on a server. The client refuses one outright, before any request is
made.
The session
| Where it lives | |
|---|---|
| Access token | Memory only (on your server, the session cookie). Lasts 15 minutes; the client refreshes it before it expires. |
| Refresh token | The storage you choose. In a browser the default is localStorage, so a reload keeps the user signed in. On your server, a cookie on your own domain. |
createClient({ url, appUid, storage: "local" }); // the browser default
createClient({ url, appUid, storage: "session" }); // one tab, gone when it closes
createClient({ url, appUid, storage: "memory" }); // nothing kept; the default outside a browser
createClient({ url, appUid, storage: mySecureStore }); // { getItem, setItem, removeItem }, sync or asynclocalStorage is readable by any script on your page, as all browser storage is. Refresh tokens are
single-use: when one is presented twice, the session ends for every holder of it, so a copied token
stops working the moment the real one is used.
Tabs share one session. Only one refreshes at a time and the others pick up its result, so any number of open tabs stays signed in. Signing out in one tab signs out all of them.
auth.onChange tells you when the session starts, refreshes, switches organization or ends, in this
tab or another:
authoric.auth.onChange(({ event, session, reason }) => {
if (event === "signedOut") showSignIn(reason); // "signed_out", or why the server ended it
});Errors
Every failure is an AuthoricError with the API's status, code, message, details and
requestId. Branch on code; the error codes page lists them, and
the package types them.
import { isAuthoricError } from "@authoric/js";
try {
await authoric.from("invoices").update(uid, { total: 0 });
} catch (error) {
if (isAuthoricError(error) && error.code === "TABLE_LOCKED") showReadOnly();
else throw error;
}An error is safe to log: it carries the server's envelope and never a token or a request body.
The client waits out what the server asks it to: an app waking from a pause (APP_WAKING), a restore
in progress or a rate limit, each for the time in Retry-After and once. It sends a write again only
when the write carries an Idempotency-Key, which every table write does by default, so a retry never
writes twice.
In this section
- Signing in: every sign-in method, two-factor, OAuth, organizations and the user's own account.
- Server-side sign-in: the session in a cookie on your own domain, for pages your server renders.
- Rows and realtime: queries, counts, batch writes, live changes and custom actions.
- Files: uploads, downloads and links.
- Teams and roles: organizations, members, invitations and roles.
- Billing: a pricing page, payments and entitlements.
- Typed tables: TypeScript types generated from your app's schema.