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

# Widget Authentication

> Secure the ChatterMate chat widget with server-generated token authentication so signed-in users are identified and their conversations appear in the agent inbox.

# Widget Authentication

Secure your embedded chat widget with token-based authentication. ChatterMate supports both public and authenticated access modes to fit your application's needs.

## Authentication Modes

ChatterMate offers two authentication modes for your widget:

<Tabs>
  <Tab title="Optional (Default)">
    ### Public Access Mode

    The default mode allows anonymous visitors to start conversations without authentication.

    **How it works:**

    * Token is automatically generated when the widget initializes
    * Visitors can chat immediately without signing in
    * Email collection is optional (based on chat style settings)
    * Conversation history is linked to the generated token

    **Best for:**

    * Public support websites
    * Documentation assistants
    * General Q\&A interfaces
    * Lead generation chatbots
  </Tab>

  <Tab title="Required">
    ### Authenticated Access Mode

    Require a valid token before users can start chatting. Enable this for secure, authenticated applications.

    **How it works:**

    * Widget requires a pre-generated token to initialize
    * Your backend requests the token from ChatterMate with the user's details
    * Conversations are linked to a stored customer (matched by email)
    * Previous conversation history loads automatically

    **Best for:**

    * Customer portals
    * SaaS applications
    * Internal support tools
    * Apps with user authentication

    <Note>
      Enable required authentication by setting `require_token_auth: true` on your agent configuration.
    </Note>
  </Tab>
</Tabs>

## How Token Authentication Works

Authenticated mode uses **server-to-server token generation**. Your backend calls ChatterMate's `/generate-token` endpoint with a **Widget App API key** and the user's details. ChatterMate creates (or matches) a customer record, then returns a short-lived JWT that the widget uses to start the chat.

<Note>
  You do **not** sign your own JWTs. ChatterMate issues and signs the token — that's how it registers the token for revocation and links the conversation to a stored customer. All you provide is your API key and the user's email/name. (Your `CONVERSATION_SECRET_KEY` is an internal server secret and is never used by integrators.)
</Note>

### What you need

<Steps>
  <Step title="Create a Widget App (API key)">
    In the ChatterMate dashboard, open **Widget Apps** and create an app. Copy the API key — it is shown only once. Treat it as a server-side secret.
  </Step>

  <Step title="Require authentication (optional)">
    Set `require_token_auth: true` on your agent to reject anonymous visitors so a token is always required.
  </Step>
</Steps>

### Token flow

<Steps>
  <Step title="Generate a token (server-side)">
    When a signed-in user opens a page with the widget, your backend calls `POST /api/v1/generate-token` with your API key and the user's email and name.
  </Step>

  <Step title="Pass the token to the widget">
    Return the token to your page and set `window.chattermateToken` before the widget script loads.
  </Step>

  <Step title="ChatterMate links the customer">
    ChatterMate stores the email and name as a **customer** (matched by email) and links the conversation to it — so the user's email and name appear in the agent inbox, and their history reloads automatically.
  </Step>
</Steps>

## Implementation

### 1. Generate a token on your backend

Call `/generate-token` with your Widget App API key in the `Authorization` header. ChatterMate returns a signed token bound to the customer.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.chattermate.chat/api/v1/generate-token \
    -H "Authorization: Bearer YOUR_WIDGET_APP_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "widget_id": "YOUR_WIDGET_ID",
      "customer_email": "user@example.com",
      "customer_name": "John Doe",
      "ttl_seconds": 3600
    }'
  ```

  ```javascript Node.js theme={null}
  async function generateWidgetToken(email, name) {
    const res = await fetch('https://api.chattermate.chat/api/v1/generate-token', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${process.env.CHATTERMATE_WIDGET_APP_API_KEY}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        widget_id: 'YOUR_WIDGET_ID',
        customer_email: email,   // stored as the customer + shown in the inbox
        customer_name: name,
        ttl_seconds: 3600,       // 60–86400 (default 3600)
      }),
    });
    const { data } = await res.json();
    return data.token;
  }
  ```

  ```python Python theme={null}
  import os, requests

  def generate_widget_token(email: str, name: str) -> str:
      res = requests.post(
          "https://api.chattermate.chat/api/v1/generate-token",
          headers={"Authorization": f"Bearer {os.environ['CHATTERMATE_WIDGET_APP_API_KEY']}"},
          json={
              "widget_id": "YOUR_WIDGET_ID",
              "customer_email": email,   # stored as the customer + shown in the inbox
              "customer_name": name,
              "ttl_seconds": 3600,        # 60–86400 (default 3600)
          },
      )
      return res.json()["data"]["token"]
  ```
</CodeGroup>

The response contains the token and its expiry:

```json theme={null}
{
  "success": true,
  "data": {
    "token": "eyJhbGci...",
    "widget_id": "YOUR_WIDGET_ID",
    "expires_in": 3600,
    "expires_at": "2026-07-06T18:00:00+00:00",
    "created_at": "2026-07-06T17:00:00+00:00"
  },
  "message": "Token generated successfully. Expires in 3600 seconds."
}
```

<Note>
  `customer_email` is optional — omit it and ChatterMate creates an anonymous customer. Passing it is what links the conversation to a named customer in the inbox, and if the same email returns later the existing customer (and their history) is reused. `customer_name` updates the stored name when it changes.
</Note>

### Passing extra customer metadata

Pass `custom_data` to attach arbitrary fields to the customer — for example a student's name and coaching center for a tutoring app, or an account tier and plan for a SaaS app. ChatterMate stores these on the customer record and shows them to agents in the chat inbox, right alongside the name and email.

```json theme={null}
{
  "widget_id": "YOUR_WIDGET_ID",
  "customer_email": "parent@example.com",
  "customer_name": "Priya Krishnan",
  "custom_data": {
    "student_name": "Aarav Krishnan",
    "center_name": "Special Academy U12"
  },
  "ttl_seconds": 3600
}
```

<Note>
  `custom_data` is capped at 20 keys and 4KB serialized. Calling `/generate-token` again for the same customer **merges** new keys into what's already stored — existing keys are overwritten if present in the new call, and any keys you don't send are left untouched.
</Note>

### 2. Pass the token to the widget

Set `window.chattermateToken` **before** the loader script runs:

```html theme={null}
<script>
  window.chattermateId = 'YOUR_WIDGET_ID';
  window.chattermateToken = 'GENERATED_TOKEN';   // from /generate-token
</script>
<script src="https://app.chattermate.chat/webclient/chattermate.min.js"></script>
```

The widget reads `window.chattermateToken`, sends it as a `Bearer` token, and ChatterMate resolves it back to the stored customer for the whole conversation.

### What's inside the token

You don't build this yourself — ChatterMate signs it — but for reference the issued token carries:

| Field                 | Description                                                            |
| --------------------- | ---------------------------------------------------------------------- |
| `sub` / `customer_id` | ChatterMate customer id (derived from the email)                       |
| `widget_id`           | The widget the token is bound to                                       |
| `customer_email`      | Email you supplied (stored on the customer)                            |
| `customer_name`       | Name you supplied                                                      |
| `custom_data`         | Extra fields you supplied (merged into the customer's stored metadata) |
| `jti`                 | Token id, used for revocation                                          |
| `exp`                 | Expiration timestamp                                                   |

## Security Features

<CardGroup cols={2}>
  <Card title="Organization Isolation" icon="building">
    Tokens are scoped to your organization. Cross-organization access is prevented.
  </Card>

  <Card title="Signature Verification" icon="shield-check">
    All tokens are cryptographically signed and verified on each request.
  </Card>

  <Card title="Widget Binding" icon="link">
    Tokens are bound to specific widgets, preventing cross-widget token reuse.
  </Card>

  <Card title="Revocable & Short-Lived" icon="lock">
    Every token has a JTI and a TTL (60s–24h), so it can be revoked and expires quickly.
  </Card>
</CardGroup>

<Warning>
  Never expose your **Widget App API key** in client-side code. Call `/generate-token` only from your backend, and hand the browser just the short-lived token it returns.
</Warning>

## Best Practices

1. **Token Expiration**
   * Keep `ttl_seconds` short (default 1 hour); the range is 60s–24h
   * Request a fresh token per page load or session rather than reusing long-lived ones
   * Handle expired-token errors by re-requesting a token

2. **Secure Generation**
   * Call `/generate-token` server-side only, with the API key in an environment variable
   * Regenerate the key from **Widget Apps** if it is ever exposed

3. **Customer Identification**
   * Always pass `customer_email` so conversations are attributed to a named customer in the inbox
   * Keep the same email for a returning user so their history and customer record are reused
   * Pass `customer_name` to show a friendly name to your agents
   * Use `custom_data` for context agents need at a glance (e.g. account tier, plan, or in a tutoring app the student's name and center) — it shows up in the inbox next to the customer's name and email

## Troubleshooting

<AccordionGroup>
  <Accordion title="401 Unauthorized from /generate-token">
    * Confirm the `Authorization: Bearer <API_KEY>` header uses a valid **Widget App** key (not your account password or the widget id)
    * Make sure the key hasn't been regenerated/deactivated in the dashboard
    * Check the `widget_id` in the body belongs to the same organization as the API key
  </Accordion>

  <Accordion title="Widget shows 'Token required' / won't load with a token">
    * The agent has `require_token_auth: true`, so `window.chattermateToken` must be set **before** the loader script runs
    * Verify the token isn't expired (check `expires_at`)
    * Check the browser console for JavaScript errors
  </Accordion>

  <Accordion title="Customer / email not showing in the inbox">
    * You must pass `customer_email` (and ideally `customer_name`) to `/generate-token` — a self-signed JWT or a token without an email won't create a named customer
    * Reuse the same email for the same user so the existing customer is matched instead of a new one being created
  </Accordion>
</AccordionGroup>

## What's Next?

After configuring authentication:

1. Set up your widget integration
2. Configure chat customization options
3. Test with authenticated and anonymous users

<Card title="Widget Integration" icon="puzzle-piece" href="/features/widget">
  Learn how to integrate the widget into your website
</Card>
