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

# Authentication & identity

> Publishable keys and signed-in user identity

Two kinds of credentials matter to an integrator:

* The **publishable key** identifies your workspace to the chat runtime. It ships in your app and is not a secret.
* **End-user identity** tells Chatropic who is chatting, so conversations land in **Inbox** under the right person and authenticated actions run against the right account.

## Publishable keys

Copy the key from **Deploy > Mobile app > Embed** or **Deploy > Chat widget > Embed** in the dashboard. Keys look like `cpk_live_<random>` and are scoped to widget runtime calls only: chat, history, feedback, and voice. They cannot read or modify workspace configuration.

```tsx theme={null}
<ChatWidgetLauncher publishableKey="cpk_live_..." />
```

The web embed uses the same publishable-key model. Snippets copied from **Deploy > Chat widget > Embed** load from `https://chatropic.com/embed/key/{publishable-key}`.

<Note>
  Workspace API keys (managed under **Deploy > API keys**) are server credentials. Never embed them in a mobile app or web page.
</Note>

## Signed-in user identity

When your app knows who is logged in, pass user props so Chatropic can associate the conversation with that person:

```tsx theme={null}
<ChatWidgetScreen
  publishableKey="cpk_live_..."
  endUserId={user.id}
  userName={user.name}
  userEmail={user.email}
/>
```

| Prop        | Purpose                                                            |
| ----------- | ------------------------------------------------------------------ |
| `endUserId` | Stable app user id. Becomes `{{end_user_id}}` in action templates. |
| `userName`  | Display name shown in **Inbox** and escalation alerts.             |
| `userEmail` | Email shown alongside the name in **Inbox** and alerts.            |

## Proving identity with a signed token

For actions that touch real user data, an attacker should not be able to impersonate another user by editing `endUserId` in a modified client. To prevent that, pass an `identityToken`: a JWT that your backend signs with the workspace **identity signing secret**, generated under **Actions > Manage tokens** when you configure a customer-login token.

Sign the JWT on your backend with `HS256`. The `sub` claim must match the `endUserId` you pass to the SDK:

```js theme={null}
// Your backend, not the app
import jwt from "jsonwebtoken";

const identityToken = jwt.sign(
  { sub: "user_123", exp: Math.floor(Date.now() / 1000) + 3600 },
  identitySecret,
  { algorithm: "HS256" }
);
```

Then pass it to the widget:

```tsx theme={null}
<ChatWidgetScreen
  publishableKey="cpk_live_..."
  endUserId="user_123"
  identityToken={identityToken}
/>
```

<Warning>
  Never sign identity JWTs inside the app or in browser code. Generate them on your backend after the user authenticates, and hand the token to the client session.
</Warning>

## Agent BFF pattern for signed-in apps

When your API actions call **your own backend**, prefer a static service token plus `endUserId` over forwarding the user's own bearer token into chat:

1. In **Actions > Manage tokens**, create a **Static value** token (for example `my_bff`).
2. Point actions at your backend with `Authorization: Bearer {{token.my_bff}}` and `X-End-User-Id: {{end_user_id}}` headers.
3. Mount the widget with `endUserId={user.id}` so the header resolves to the signed-in user.

See [Manage tokens](/user-guides/actions/manage-tokens#agent-bff-signed-in-apps) for the dashboard side of this setup.

<CardGroup cols={2}>
  <Card title="React Native SDK" icon="mobile-screen" href="/developer-guides/integration/react-native-sdk">
    Where these props fit in a full integration.
  </Card>

  <Card title="Error handling" icon="triangle-exclamation" href="/developer-guides/integration/error-handling">
    What users see when identity or actions fail.
  </Card>
</CardGroup>
