= The Ulabase Kit
:nav-title: Ulabase Kit
:description: The Ulabase Kit is the client code for your app: sign-up, sign-in, sessions, teams, invitations and payments, for React, Angular, Vue, Next.js and Nuxt.
:keywords: frontend SDK, React authentication, Angular auth, Vue auth, Next.js backend, sign-up and login library, useAuth, usePayments
:group: Tools
:order: 20
The **Ulabase Kit** is a package of client code for your app. It talks to your service for you: sign-up, sign-in, email verification, password reset, teams and invitations, and, for an app that sells something, subscriptions and orders.
Use it so your app gets these flows in a few calls. For example, the kit renews the session before it expires, and handles the return from Stripe after a checkout.
[source,bash]
----
npm install @ulabase/kit
----
[source,typescript]
----
import { checkSession, login, logout } from '@ulabase/kit';
const config = { apiBaseUrl: 'https://c0ffee.ulabase.app' };
const user = await checkSession(config); // UserInfo, or null
await login(config, 'user@example.com', 'secret');
await logout(config);
----
Every function takes the same `config` as its first argument. There is nothing to initialise or
register, and no state in a module global.
== What it saves you
Sign-up, sessions and checkout each take several steps.
Signing up is a `POST`, an email, a verification link that lands on a different origin, a redirect
carrying a token in a URL fragment, and a token to store. A session is a JWT that expires in
fifteen minutes and has to be renewed before it does, from a timer that survives a backgrounded
tab. A checkout is a redirect to Stripe, a return to a page that knows which order came back, and a
webhook that may arrive after the customer does.
The kit handles those flows against your service's sign-up and Stripe features. It has no
dependencies of its own and works with any framework.
== The packages
[cols="1,3"]
|===
| Package | What it adds
| `@ulabase/kit`
| The core. Plain TypeScript, zero dependencies, works with any framework or none. Everything below is built on it.
| `@ulabase/kit-ng`
| Angular: `provideRhAuth()`, `RhAuthService` and `RhPaymentsService` on signals, route guards, and an HTTP interceptor that attaches the token and clears the session on `401`.
| `@ulabase/kit-react`
| React: `RhAuthProvider`, `useAuth()`, `usePayments()`, route guards. A `/next` subpath adds Next.js: middleware refresh, a first-party session cookie, the fragment→cookie bridge, and server actions.
| `@ulabase/kit-vue`
| Vue: `createRhAuth()`, `useAuth()`, `usePayments()`, navigation guards. A `/nuxt` subpath does for Nuxt what `/next` does for Next.
|===
Each adapter wraps the core: the same functions, exposed the way that framework expects state to
arrive. Payments have their own API, apart from auth: a subscription loads on sign-in, reloads when
the user switches team, and stays untouched when the service has no `stripe` feature.
Each adapter installs the core as a dependency. Each package's README has the exact line.
== Setting it up
Angular, in `app.config.ts`:
[source,typescript]
----
providers: [provideRhAuth({ apiBaseUrl: environment.apiUrl })]
----
React, near the root:
[source,tsx]
----
----
Vue, in `main.ts`:
[source,typescript]
----
const rhAuth = createRhAuth({ apiBaseUrl: import.meta.env.VITE_API_URL });
app.use(rhAuth);
router.beforeEach(rhAuth.authGuard);
----
In all three the session is restored once at start-up, before the first guard runs, so a page
reload keeps a signed-in user where they were. Until then `initializing` is true: show a spinner
while it is.
== Sessions
The token is a JWT that lasts fifteen minutes. The kit renews it at 80% of its life, so a tab left
open stays signed in. If it expires anyway (a sleeping laptop, a tab in the background for an hour),
the next call gets a `401` and the session is cleared: the user sees that they are signed out.
=== Bearer token or cookie
[WARNING]
====
The kit supports two modes. For a Ulabase service, use bearer.
**Bearer** (the default) keeps the token in `localStorage` and sends
`Authorization: Bearer `. It works cross-origin.
**Cookie** mode has the server manage an HttpOnly JWT cookie, and needs the app and the service to
share an origin. Your service lives on `*.ulabase.app` and your app does not, so that cookie is
*third-party* on every request the page makes. Safari and Firefox block it by default, and in
Chrome it is the user's choice. **No CORS configuration changes this**: the browser drops the cookie
before CORS is consulted.
Stay on `'bearer'` unless the app is served from the service's own origin.
====
Next.js and Nuxt can use a cookie: a *first-party* one, set by your own server and holding the
same bearer token. It needs no cookie support from the service. The `/next` and `/nuxt` subpaths do
this for you.
== What it covers
**Accounts**: `register`, `verify`, `login`, `logout`, `checkSession`, `getUserInfo`,
`renewToken`, `forgotPassword`, `resetPassword`, `changePassword`, `updateProfile`. The flows
of xref:signup-mgmt.adoc[Sign-up and login], with the redirects and token deliveries already handled.
**Teams**: `getTeams`, `switchTeam`, `createTeam`, `listTeamMembers`, `updateMemberRole`,
`removeMember`, and the invitation half: `invite`, `getInvitation`, `activate`, `acceptInvite`,
`resendInvite`. The token carries no team: after `switchTeam`, `user.team` reads the new one from `/users/me`.
**Consents**: `acceptConsents`, for accepting terms and privacy policy. Use it with
xref:guards.adoc[Guards], which make acceptance mandatory on the server, where the client cannot
skip it.
**Payments**: `getPlans`, `createCheckoutSession`, `openBillingPortal`, `getSubscription`,
`waitForSubscription`, and seat licences with `getLicenses` / `grantLicense` / `revokeLicense`.
For a shop with one-off orders: `getCatalog`, `createOrder`, `getOrder`, `waitForOrder`,
`readOrderRef`. You need no Stripe.js and no publishable key: every Stripe page is hosted, and the
kit gives you its URL to navigate to. See xref:stripe.adoc[Stripe billing] for the service side.
The customer's browser usually comes back to your site before Stripe's webhook does.
`waitForOrder` waits for the webhook, and when it is late it rejects with a `WaitTimeoutError`, so
you can show "still confirming" for a payment that has not failed.
**Cart**: lines, quantities, subtotal and persistence, ready for any shop. The logic is pure and
takes the lines it works on, and each framework wraps it: `useCart()` in React and Vue,
`RhCartService` in Angular.
[source,tsx]
----
const cart = useCart();
cart.add({ productId: 'tee-classic/yellow-l', name: 'Classic T-shirt',
unitAmount: 2500, options: { colour: 'yellow', size: 'L' } });
await createOrder(config, cart.orderItems);
----
`orderItems` is the cart in the shape `createOrder` takes. Names, prices and pictures stay out:
the service reads them from its own catalog. The chosen **options go with the order, as the line's
`metadata`**. A reference like `tee-classic/yellow-l` says which row of the catalog was bought; the
options give the seller "yellow, L" in separate fields.
The cart works without a session: it needs no `AuthConfig` and no auth provider, so visitors can
fill a basket before they sign in. It becomes an order at `createOrder`, which needs a config. It
lives in `localStorage`, so a reload keeps it; pass a `storageKey` when two of your apps share an
origin.
Errors are thrown as an `ApiError`, `{ status, message }`, with the server's own message in it.
== A note on the users collection
`register` sends whatever you give it. If the service's `users` collection has a JSON Schema, extra
fields are validated against it; if it has none, the server **silently drops** them and still
answers `201`. If a profile field never appears, this is the usual cause.
== Related pages
* xref:cli.adoc[The `ulabase` CLI]: configure the service the kit talks to from a file in git
* xref:tokens.adoc[Tokens]: what each token reaches
* xref:stripe.adoc[Stripe billing]: the `stripe` feature, its keys, and the permissions a guest checkout needs
* xref:guards.adoc[Guards]: server-side rules the client cannot skip
* xref:starters.adoc[Starters]: complete apps built on the kit
* https://github.com/ulabase/kit[ulabase/kit]: the source; each package's README has the full API