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

# Authentication

> Choose how the AI Chat Widget should recognize visitors, protect conversation history, and support signed-in customers.

Use this page when you need to decide who the widget should treat as the same person, and how much trust to place in the identity data you pass in.

<Tip>
  If your goal is to get the widget on the page first, start with **[Install Widget](/widget/install-widget)**.
</Tip>

<Info>
  Want to see how identity settings look on screen? The **[Playground](/widget/playground)** lets you toggle visitor data collection and other options live, then copy the matching snippet.
</Info>

## Start With The Right Identity Model

<AccordionGroup>
  <Accordion title="Anonymous visitor" icon="user">
    Lowest friction. Best for public support chat where history stays tied to the same browser.
  </Accordion>

  <Accordion title="Non-verified visitor" icon="id-card">
    Best when you want name, email, or lightweight personalization without server-issued identity.
  </Accordion>

  <Accordion title="Verified customer" icon="shield-check">
    Best when signed-in customers should keep history across devices and you need stronger protection against impersonation.
  </Accordion>
</AccordionGroup>

## What Changes Between Non-Verified And Verified

<AccordionGroup>
  <Accordion title="History access" icon="clock">
    Verified customers can keep history across devices. Anonymous and non-verified visitors should be treated as browser-bound or device-bound experiences.
  </Accordion>

  <Accordion title="Trust level" icon="shield">
    <Tooltip tip="When true, the widget shows a built-in form asking for the visitor's name and email before chat begins.">`collectUserData`</Tooltip> and <Tooltip tip="Browser-provided visitor details (name, email, avatar) for personalization — does not prove identity.">`user.data`</Tooltip> help you personalize the chat, but they do not prove identity. <Tooltip tip="A server-issued JWT that verifies the visitor's identity, enabling cross-device chat history and stronger impersonation protection.">`user.token`</Tooltip> is the strong identity path.
  </Accordion>

  <Accordion title="Custom data handling" icon="database">
    Browser-provided custom data is useful, but should be treated with caution. Server-authenticated custom data is the safer choice when it affects support decisions.
  </Accordion>
</AccordionGroup>

## Two Tokens, Two Jobs

Do not confuse these tokens:

<CardGroup cols={2}>
  <Card title="Widget token" icon="key" href="/widget/install-widget">
    This token loads your organization’s widget. Get it from the widget setup flow, then use it when you install the widget.
  </Card>

  <Card title="Authenticated contact token" icon="shield-check" href="/api-reference/widget/authenticate-contact">
    This token identifies a verified customer. Your backend requests it, then passes it to `user.token`.
  </Card>
</CardGroup>

## Implementation Paths

<Tabs>
  <Tab title="Collect">
    <Steps>
      <Step title="Choose this path for public visitors">
        Use this when visitors are not signed in and you want the widget to ask for basic details before chat begins.
      </Step>

      <Step title="Turn on built-in collection">
        Add `collectUserData: true` to the widget options.

        ```tsx theme={"dark"}
        const options = {
          token: '<WIDGET_TOKEN>',
          collectUserData: true,
        };
        ```
      </Step>

      <Step title="Test the welcome flow">
        Confirm the widget asks for the visitor’s name and email before they enter the chat.
      </Step>
    </Steps>

    <Note>
      This creates a **non-verified** identity. It improves context for your team, but it should not be treated as strong proof that the visitor owns that email address.
    </Note>
  </Tab>

  <Tab title="Browser">
    <Steps>
      <Step title="Choose this path for lightweight personalization">
        Use this when your app already knows who the visitor is and you want the widget to start with that information.
      </Step>

      <Step title="Pass the visitor data in user.data">
        Send the fields you already know from the browser.

        ```tsx theme={"dark"}
        const options = {
          token: '<WIDGET_TOKEN>',
          user: {
            data: {
              name: user.name,
              email: user.email,
              avatarUrl: user.avatarUrl,
              customData: user.customData,
            },
          },
        };
        ```
      </Step>

      <Step title="Use it for convenience, not proof">
        This is best when the widget should feel personalized, but you do not need strong identity guarantees.
      </Step>
    </Steps>

    <Note>
      This is still **non-verified** because the browser can be tampered with.
    </Note>
  </Tab>

  <Tab title="Server">
    <Steps>
      <Step title="Choose this path for signed-in customers">
        Use this when customers sign in to your product and should keep history across devices.
      </Step>

      <Step title="Request a verified contact token on your backend">
        Call the widget authentication API from your server.

        <CodeGroup>
          ```bash cURL theme={"dark"}
          curl -X POST https://api.open.cx/widget/authenticate-user \
            -H "Authorization: Bearer <ORG_API_KEY>" \
            -H "Content-Type: application/json" \
            -d '{
              "email": "jane@example.com",
              "name": "Jane Doe",
              "customData": {
                "plan": "enterprise",
                "accountId": "acct_123"
              }
            }'
          ```

          ```ts fetch theme={"dark"}
          const response = await fetch('https://api.open.cx/widget/authenticate-user', {
            method: 'POST',
            headers: {
              Authorization: 'Bearer <ORG_API_KEY>',
              'Content-Type': 'application/json',
            },
            body: JSON.stringify({
              email: user.email,
              name: user.name,
              customData: {
                plan: user.plan,
                accountId: user.accountId,
              },
            }),
          });

          const { token: authenticatedContactToken } = await response.json();
          ```
        </CodeGroup>
      </Step>

      <Step title="Pass the token into the widget">
        Use the returned token through `user.token`.

        ```tsx theme={"dark"}
        const options = {
          token: '<WIDGET_TOKEN>',
          user: {
            token: authenticatedContactToken,
          },
        };
        ```
      </Step>
    </Steps>

    <Tip>
      This is the recommended path for **signed-in customer support**.
    </Tip>
  </Tab>
</Tabs>

## Extra Identity Controls

### Scope History With `externalId`

Use <Tooltip tip="An optional identifier that scopes conversation history to a specific account, workspace, or tenant — so the same person sees the right history for each context.">externalId</Tooltip> when the same person can belong to multiple accounts, workspaces, or tenants inside your product.

```tsx theme={"dark"}
const options = {
  token: '<WIDGET_TOKEN>',
  user: {
    token: authenticatedContactToken,
    externalId: currentWorkspaceId,
  },
};
```

This keeps history aligned to the right account context instead of treating every conversation for that email address as one shared history.

### Prefill Or Collect More Fields

`name` and `email` are the visitor details the widget can show or collect. <Tooltip tip="Pre-populates the name and email fields in the widget's data collection form with values your app already knows.">`prefillUserData`</Tooltip> fills those fields before the visitor types, while <Tooltip tip="Adds custom fields beyond name and email to the built-in data collection form.">`extraDataCollectionFields`</Tooltip> adds more fields to the collection form.

If you are using the widget’s built-in data collection flow, you can:

* prefill `name` and `email` with `prefillUserData`
* collect additional fields with `extraDataCollectionFields`

These are good onboarding improvements for public support flows, but they do not replace verified identity.

## API Notes For Server-Side Authentication

The widget authentication API is designed for your backend:

<CardGroup cols={4}>
  <Card title="1. Call the endpoint" icon="code">
    Call `POST /widget/authenticate-user` from your backend.
  </Card>

  <Card title="2. Use the right API key" icon="key">
    Authenticate with an org API key that has <Tooltip tip="An API permission scope required to authenticate widget contacts on behalf of your organization.">`widget:write`</Tooltip>.
  </Card>

  <Card title="3. Return or store the token" icon="database">
    Store the contact token in your app flow or return it to the frontend.
  </Card>

  <Card title="4. Pass it to user.token" icon="shield-check">
    Give the widget the verified token through `user.token`.
  </Card>
</CardGroup>

<CardGroup cols={1}>
  <Card title="Widget Authentication API" icon="arrow-right" href="/api-reference/widget/authenticate-contact">
    Open the full API contract, request example, and response shape for authenticated contact tokens.
  </Card>
</CardGroup>

### If Your AI Actions Need Request Data

<Tooltip tip="Custom HTTP headers sent with AI action requests to your APIs.">`headers`</Tooltip>, <Tooltip tip="Custom query parameters appended to AI action request URLs.">`queryParams`</Tooltip>, and <Tooltip tip="Custom properties merged into the body of AI action requests.">`bodyProperties`</Tooltip> do not identify the visitor. They add request data to the HTTP calls your AI actions make to your own APIs.

<Info>
  Use widget authentication to decide **who the visitor is**. Use action request fields to decide **what your AI action sends to your API**. If you need help with that second part, see [Authentication](/actions/authentication).
</Info>

## Related Documentation

<CardGroup cols={2}>
  <Card title="Install Widget" icon="plug" href="/widget/install-widget">
    Load the widget with HTML, React, or headless setup.
  </Card>

  <Card title="Configuration" icon="gear" href="/widget/configuration">
    Prefill data, prompts, routing, and advanced widget behavior.
  </Card>

  <Card title="Conversation Sessions" icon="route" href="/widget/conversation-sessions">
    See how identity choices change history and continuity.
  </Card>

  <Card title="Mobile Support" icon="phone" href="/widget/native-mobile">
    Use verified contact tokens inside mobile WebViews.
  </Card>
</CardGroup>
