> ## Documentation Index
> Fetch the complete documentation index at: https://docs.firstflow.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Identity & auth

> FirstFlow has no auth system of its own. You bring your own auth, pass a user id, and unidentified visitors get a stable anonymous id.

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.

```tsx theme={null}
<FirstflowProvider
  user={{ id: user.id, traits: { plan: user.plan, role: user.role } }}
  experiences={experiences}
  persistence={persistence}
>
```

* **`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](/concepts/triggers-and-audience) 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.

```tsx theme={null}
// No user yet runs in anonymous scope
<FirstflowProvider experiences={experiences} persistence={persistence}>
```

* 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:

```tsx theme={null}
import { getAnonymousId } from "@firstflow/runtime";

const anonId = getAnonymousId(); // stable per browser
```

## 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](/server/overview).

Scope follows from whether you pass it:

| You pass on the server call             | Scope                                                        |
| --------------------------------------- | ------------------------------------------------------------ |
| `userId` only                           | **User scope** a standalone trace / LLM-call row             |
| `userId` + `sessionId`/`conversationId` | **Conversation + user scope** also grouped into a transcript |

## 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](/self-hosting/oauth-providers); 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](/self-hosting/oauth-providers) policies, then review [what you own](/self-hosting/responsibilities) and the [production checklist](/self-hosting/production).
