uidudevelopers
Foundations

Authentication

The three ways a request reaches uidu — public token, account Bearer, custom-app session — and where each may run.

What an app looks like — a landing page, a blog, a dashboard, a booking tool — doesn't decide how it authenticates. Who the request acts for does:

Acting forTokencreateClient optionRuns
Anyone — public readspublic tokenpublicTokenanywhere, including the browser
The workspace — every write, and private dataaccount BearerapiKeyyour server or the CLI only
The signed-in member — an app inside uidusession from the host pagefromBridge(bridge)the browser, inside uidu only

One app can mix the rows: public pages rendered on the server with the public token, a contact form submitted through a server action with the Bearer, and a members' area that only works when uidu frames it.

Every domain page says at the top which token its reads and writes need, and the client reference says it per function.

Public token — reads for anyone

Read-only access to what a workspace publishes: CMS pages, events, stories, forms, courses, donation campaigns, the help center. It is safe to ship in browser code.

Get it from Workspace → Settings → Public tokens.

import { createClient } from '@uidu/client';

export const uidu = createClient({
  workspace: process.env.UIDU_WORKSPACE!,
  publicToken: process.env.UIDU_PUBLIC_TOKEN,
});

Private data — contacts and deals, people, goals, bookings, campaigns — isn't readable with it: the query succeeds and returns nothing (an empty list, or null). If a list is unexpectedly empty, check the domain's header before debugging the query.

Bearer — the workspace

An account access token, sent as Authorization: Bearer …. It acts as the account it belongs to, so it can do whatever that account's role in the workspace allows: read private data, and run every write — including the visitor-facing ones (form responses, donations, RSVPs, job applications).

// lib/uidu.ts — imported only from server code
import { createClient } from '@uidu/client';

export const uidu = createClient({
  workspace: process.env.UIDU_WORKSPACE!,
  publicToken: process.env.UIDU_PUBLIC_TOKEN,
  apiKey: process.env.UIDU_API_KEY, // server-only
});

Never in the browser

Keep apiKey on the server: a Server Component, a server action, a route handler, a script, or the CLI. Don't prefix it NEXT_PUBLIC_, and don't pass it to <UiduProvider> (which has no apiKey prop for this reason). A visitor submitting a form goes through a server action that calls createFormResponse with this client — see Forms.

Get one from Workspace → Settings → API keys, or run uidu login, which signs you in through the browser and stores a token in ~/.uidu/config.json. Set it as UIDU_API_KEY where your server runs. Writes and their errors are covered in Writes.

Session — the signed-in member, inside uidu

A custom app runs in an iframe inside uidu. The host page hands it a short-lived session (five minutes, refreshed for you) over postMessage: the app can do what that member can do, and no more. There is no token to configure.

'use client';
import { UiduAppProvider } from '@uidu/react';

// Inside, useUiduClient() / useUiduApp() give you a session-backed client.
<UiduAppProvider>{children}</UiduAppProvider>;

Outside React: connect() from @uidu/app-bridge, then createClient(fromBridge(bridge)).

Three rules follow from where the session lives:

  1. It only exists in the browser. It arrives after the page loads, so Server Components and server actions never have it — pages that show member data are 'use client'.
  2. It only works from the app's own origin. Don't forward it to a backend of yours to call uidu from there.
  3. It reaches less than a Bearer. The app's own Models, and read-only the workspace's goals. Everything else comes back as an error for now.

Choosing, in one line each

  • Rendering public content (site, blog, events, careers): public token, on the server or in the browser.
  • Anything that writes, or reads private data: Bearer, on the server.
  • An app members open inside uidu: session, in the browser.

On this page