= 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