Admin API
base.auth.admin calls /auth/v1/admin/* and works only with a secret key (lb_sec_...). Other keys and user tokens get 403 service_role_required.
import { createClient } from "@potalab/base"
const admin = createClient({ url: process.env.POTALAB_BASE_URL!, key: process.env.POTALAB_BASE_SECRET_KEY! })
await admin.auth.admin.inviteUserByEmail("ann@acme.com", { redirectTo: "https://app.acme.com/welcome", data: { name: "Ann" },})await admin.auth.admin.createUser({ email: "bob@acme.com", password: "...", email_confirm: true })const { data } = await admin.auth.admin.listUsers({ perPage: 50 }) // { users, nextCursor, total }await admin.auth.admin.getUserById(id)await admin.auth.admin.updateUserById(id, { user_metadata: { plan: "pro" } })await admin.auth.admin.deleteUser(id)Generate links
Section titled “Generate links”const { data } = await admin.auth.admin.generateLink({ type: "magiclink", email: "ann@acme.com" })generateLink (invite, magiclink or recovery) returns action_link without sending an email. Deliver it yourself and treat it as a credential: do not log it. signup links are not supported, and redirectTo must pass the redirect allowlist.
Invitations
Section titled “Invitations”An invited user is created in the invited state with no password. PotaLab Base emails a single-use link valid for 7 days with ?type=invite&token=.... Your page completes it:
await base.auth.acceptInvite({ token, password })Accepting sets the password, marks the email verified and signs the user in. A resend invalidates the previous link; used or expired links fail with invite_invalid.
Metadata
Section titled “Metadata”app_metadata can only be changed by admins and is passed to the claims hook, which makes it the place for roles and plans. user_metadata is profile data users can edit.
Dashboard and Management API
Section titled “Dashboard and Management API”The dashboard Authentication → Users page and the Management API (auth:admin scope) also support searching, banning, sign-out everywhere, password reset emails, MFA reset and bulk import. Bans are checked on every sign-in path and on refresh (403 user_banned); access tokens issued before the ban stay valid until they expire.