Skip to main content
FirstFlow does not authenticate anyone. There are no FirstFlow accounts, organizations, or roles in the SDK your application already knows who its users are, and you hand that identity to the runtime. This page covers what FirstFlow expects, how anonymous visitors are handled, and how identity flows from the browser to your backend.

Bring your own auth

You pass an already-authenticated user to the provider. FirstFlow trusts that value your own auth provider (Supabase Auth, Clerk, Auth.js, your session, anything) is what verifies who the user actually is.
  • id your stable user identifier. It becomes the subject of frequency caps (once_per_user), in-progress resume, and the user_id on persisted rows.
  • traits arbitrary key/values used for audience targeting and branching (when: { "traits.plan": "pro" }).

Anonymous visitors

user is optional. Omit it (or pass no id) and the runtime falls back to a stable per-browser anonymous id, persisted in localStorage, so once_per_user caps and resume still work before someone signs in.
  • The anonymous id survives reloads, so a returning visitor keeps one identity.
  • Anonymous users carry traits.anonymous === true, so you can target or exclude them: when: { "traits.anonymous": true }.
  • When the visitor signs in, pass their real { id } to bind subsequent experiences to their account.
You can read or reuse the id directly:

The conversation id (server-side only)

The browser runtime has no conversation id FirstflowProvider persists experiences by user.id alone and never opens a backend channel. The conversation id is a server-SDK concept: an id you own, used to group a conversation’s transcript and classifier state in firstflow_conversations. Your own chat code generates it (for example crypto.randomUUID() kept in sessionStorage) and passes it to your backend’s wrapped LLM calls as firstflow: { userId, sessionId } sessionId is just an alias for conversationId. The provider neither takes nor sends it. What actually links the front-end and back-end is the shared user.id: pass the same one to the provider and to your server calls. See the Server SDK. Scope follows from whether you pass it:

Securing the data

Identity is trusted client-side, so the trust boundary is your database, not FirstFlow. The browser writes with the Supabase anon key under Row Level Security; the server SDK writes with the service_role key, which bypasses RLS and must stay server-only. Design your RLS policies around the user_id your auth issues.

Auth is your application’s job

FirstFlow has no accounts, organizations, roles, or SSO of its own. Multi-tenancy, team roles, and sign-in all live in your auth layer; FirstFlow simply reads the user.id and traits you derive from them.

Next

Define your Row Level Security policies, then review what you own and the production checklist.