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

# Identity Verification

> Authenticate users in your widget

Identity verification lets your agent know who the user is—enabling personalized support and persistent conversations.

## What You Get

| Feature               | Anonymous | Verified |
| --------------------- | --------- | -------- |
| Chat                  | ✅         | ✅        |
| Conversation history  | ❌         | ✅        |
| Personalized by name  | ❌         | ✅        |
| User-specific actions | ❌         | ✅        |

## How It Works

```
1. User logs into YOUR app
2. Your backend mints a Crow identity token (JWT signed with your Crow secret)
3. Your frontend calls window.crow('identify', { token })
4. Widget now knows who the user is
```

<Note>
  This is **not** your app's session JWT. It's a separate Crow-scoped identity token that your backend mints specifically for Crow. Your app JWT stays private.
</Note>

***

## 1. Get Your Secret

[app.usecrow.ai/deploy](https://app.usecrow.ai/deploy) → copy **Verification Secret**

Add to your backend environment:

```bash theme={null}
CROW_VERIFICATION_SECRET=your_secret_here
```

<Warning>Never expose this secret in frontend code.</Warning>

***

## 2. Create Backend Endpoint

<CodeGroup>
  ```javascript Node.js (Express) theme={null}
  const jwt = require('jsonwebtoken')

  app.get('/api/crow-token', authMiddleware, (req, res) => {
    const token = jwt.sign(
      {
        user_id: String(req.user.id),  // Required
        exp: Math.floor(Date.now() / 1000) + 3600,  // Required: 1 hour
        email: req.user.email,  // Optional
        name: req.user.name,  // Optional
      },
      process.env.CROW_VERIFICATION_SECRET,
      { algorithm: 'HS256' }
    )
    res.json({ token })
  })
  ```

  ```python Python (FastAPI) theme={null}
  import jwt, time, os
  from fastapi import Depends

  @app.get("/api/crow-token")
  async def get_crow_token(user = Depends(get_current_user)):
      token = jwt.encode(
          {
              "user_id": str(user.id),  # Required
              "exp": int(time.time()) + 3600,  # Required
              "email": user.email,  # Optional
              "name": user.name,  # Optional
          },
          os.environ["CROW_VERIFICATION_SECRET"],
          algorithm="HS256"
      )
      return {"token": token}
  ```

  ```python Python (Flask) theme={null}
  import jwt, time, os
  from flask_login import login_required, current_user

  @app.route("/api/crow-token")
  @login_required
  def get_crow_token():
      token = jwt.encode(
          {
              "user_id": str(current_user.id),
              "exp": int(time.time()) + 3600,
              "email": current_user.email,
              "name": current_user.name,
          },
          os.environ["CROW_VERIFICATION_SECRET"],
          algorithm="HS256"
      )
      return {"token": token}
  ```
</CodeGroup>

### JWT Payload

| Field     | Type   | Required | Description                 |
| --------- | ------ | -------- | --------------------------- |
| `user_id` | string | Yes      | Unique user identifier      |
| `exp`     | number | Yes      | Expiration (Unix timestamp) |
| `email`   | string | No       | User's email                |
| `name`    | string | No       | Display name                |

***

## 3. Identify in Frontend

<Tabs>
  <Tab title="React SDK (Recommended)">
    Pass `getIdentityToken` to `CrowWidget` or `CrowCopilot`. The SDK calls it on mount and auto-refreshes when the token expires — no manual polling needed.

    ```tsx theme={null}
    import { CrowWidget } from '@usecrow/ui';

    function App() {
      return (
        <CrowWidget
          productId="YOUR_PRODUCT_ID"
          apiUrl="https://api.usecrow.org"
          getIdentityToken={async () => {
            const res = await fetch('/api/crow-token');
            const { token } = await res.json();
            return token;
          }}
        />
      );
    }
    ```

    That's it. No `useEffect`, no `setInterval`, no `window.crow('identify')` calls.
  </Tab>

  <Tab title="Script Tag">
    ```javascript theme={null}
    async function identifyToCrow() {
      const res = await fetch('/api/crow-token', {
        headers: { Authorization: `Bearer ${yourAuthToken}` }
      })
      const { token } = await res.json()
      
      window.crow('identify', { token, name: userName })
    }

    // Call after login or on page load if already logged in
    identifyToCrow()

    // Refresh every 50 minutes (token expires in 60)
    setInterval(identifyToCrow, 50 * 60 * 1000)
    ```
  </Tab>
</Tabs>

***

## 4. Handle Logout

<Tabs>
  <Tab title="React SDK">
    Logout is handled automatically — when the component unmounts or the user navigates away, the session is cleared.
  </Tab>

  <Tab title="Script Tag">
    ```javascript theme={null}
    function handleLogout() {
      logout()
      window.crow('resetUser')
    }
    ```

    <Warning>Always call `resetUser` on logout to clear the previous user's session.</Warning>
  </Tab>
</Tabs>

***

## Troubleshooting

| Issue                  | Solution                                             |
| ---------------------- | ---------------------------------------------------- |
| User not identified    | Check secret matches dashboard, `user_id` is string  |
| Token invalid          | Check `exp` is in future, algorithm is HS256         |
| History not persisting | Call `identify()` on page load, not just after login |
