SDK · @manybases/js
@manybases/js — auth
Sign people up and in, keep their session, and let them out. Every method returns { data, error } and never throws.
const { data, error } = await mb.auth.signup({ email, password });
if (error) console.error(error.code, error.hint);| Method | Calls | Returns |
|---|---|---|
signup({ email, password }) | POST /v1/auth/signup | { user, session: { token }, seats } — persists the session |
login({ email, password }) | POST /v1/auth/login | the same — persists the session |
logout() | POST /v1/auth/logout | { logged_out: true } — always clears the local session, even on a refusal |
me() | GET /v1/auth/me | { user, seats } — clears the local session on a 401, and only there |
sendMagicLink({ email }) | POST /v1/auth/magic-link | { sent: true } |
verifyMagicLink(token) | GET /v1/auth/magic-link/verify | { user, session: { token }, seats } — persists the session |
verifyResetToken(token) | GET /v1/auth/reset-password/:token | { token } — checks the link without consuming it |
resetPassword({ token, password }) | POST /v1/auth/reset-password | { reset: true } — consumes the link and signs the person out everywhere |
getSession() | — | the stored token, or null |
setSession(token | null) | — | stores a token, or clears it |
user is { id, email, created_at }; seats is { used, cap }, with cap: null when the plan's cap could not be read.
Where the session lives#
By default the token is kept in localStorage, for 30 rolling days. Any injected script can read it: your Content Security Policy protects your session, the SDK cannot. Pass storage at createClient to use sessionStorage, an in-memory store or your own vault, or storage: null to keep the token in memory only. On the server, keep the token wherever your framework keeps a user's state and hand it to a per-request client with setSession.
Only three calls persist a session — signup, login, verifyMagicLink. A data-plane 401 does not clear it: a refused read does not mean the session is dead.
What the API decides#
- A seat is taken at sign-up:
seats.usedin a sign-up response counts the person who just signed up. At the cap (3 on Free, 1 000 on Builder and Studio)signupanswers402 quota_exceededand creates nothing;loginis never refused by the cap. - An e-mail already registered answers
400 validation_error; wrong credentials answer401. - Every publishable key signs users up, whoever created it — an agent's included. (Until 2026-09-07 a key created by an agent alone was inert, and
signupanswered401; that rule is removed.) See Invite users. - A magic-link or reset token that is unknown, expired or already used answers the same
401. sendMagicLinkanswers429 rate_limitedbeyond 20 requests an hour from one IP, or once today's sign-in emails are used up (50 per app, 70 across all apps, until 00:00 UTC);retryAftergives the delay. Beyond 5 requests an hour for one address it still answers{ sent: true }, and nothing is sent.verifyMagicLinkanswers402 quota_exceededwhen it would sign up a new person on an app whose seat cap is reached, or on an app in read-only mode. For an address already signed up it is a sign-in, and the cap never refuses it.
Invitation links are minted server-side, by a signed-in user (POST /v1/invites), and lead to your own sign-up page: the SDK has no method for them, the link's token is consumed by your signup call.
