> This page is for For Developers.

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://whop.ferndocs.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://whop.ferndocs.com/_mcp/server.

# Authentication

> Authenticate users for embedded chat with company-scoped tokens or OAuth

Before using the chat SDK, you need to authenticate users. Pick one of two approaches:

| Approach                                                      | Best for                                                                                            |
| ------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
| **[Company-scoped user tokens](#company-scoped-user-tokens)** | Apps that already have their own users. Your server mints Whop tokens for them — no sign-in needed. |
| **[OAuth](/developer/guides/chat/oauth)**                     | Apps that want users to sign in to Whop themselves via a sign-in page or webview.                   |

## Company-scoped user tokens

Use this approach if **your app already has its own users** (via your own auth / session system). You keep your existing login flow and mint a Whop token for whichever user is currently signed in — no extra sign-in step.

Your server exchanges your Whop API key for a short-lived user token on demand and returns it to the client. You decide which user the token is for.

### 1. Gather your credentials

You'll need three things:

1. **API key** — create one at the [Whop Developer Dashboard](https://whop.com/dashboard/developer). Treat it like a password and keep it on your server only.
2. **Company ID** — find it in your dashboard URL: `whop.com/dashboard/biz_XXXXXXXXX/`.
3. **User ID** — the user you want to authenticate. In production, derive this from your own auth / session system.

> **Note**
>
> For embedded chat, both `company_id` and `user_id` are required together when minting a token.

### 2. Create a token endpoint on your server

Add an endpoint that calls `POST https://api.whop.com/api/v1/access_tokens` with your API key and returns the resulting token to the client.

#### Next.js

**`app/api/chat/token/route.ts`**

```typescript app/api/chat/token/route.ts
import { NextResponse } from "next/server";
import Whop from "@whop/sdk";

const client = new Whop({ apiKey: process.env.WHOP_API_KEY });

export async function POST() {
  // Derive these from your own auth / session in production.
  const user_id = "user_XXXXXXXXXXXX";
  const company_id = "biz_XXXXXXXXXXXXX";

  const { token } = await client.accessTokens.create({
    company_id,
    user_id,
    scoped_actions: [
      "chat:message:create",
      "chat:read",
      "dms:read",
      "dms:message:manage",
      "dms:channel:manage",
      "support_chat:read",
      "support_chat:message:create",
    ],
  });

  return NextResponse.json({ token });
}
```

#### Express

**`server.ts`**

```typescript server.ts
import express from "express";
import Whop from "@whop/sdk";

const app = express();
app.use(express.json());

const client = new Whop({ apiKey: process.env.WHOP_API_KEY });

app.post("/api/chat/token", async (_req, res) => {
  // Derive these from your own auth / session in production.
  const user_id = "user_XXXXXXXXXXXX";
  const company_id = "biz_XXXXXXXXXXXXX";

  const { token } = await client.accessTokens.create({
    company_id,
    user_id,
    scoped_actions: [
      "chat:message:create",
      "chat:read",
      "dms:read",
      "dms:message:manage",
      "dms:channel:manage",
      "support_chat:read",
      "support_chat:message:create",
    ],
  });

  res.json({ token });
});

app.listen(3000);
```

#### cURL

```bash
curl -X POST https://api.whop.com/api/v1/access_tokens \
  -H "Authorization: Bearer $WHOP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "company_id": "biz_XXXXXXXXXXXXX",
    "user_id": "user_XXXXXXXXXXXX",
    "scoped_actions": [
      "chat:message:create",
      "chat:read",
      "dms:read",
      "dms:message:manage",
      "dms:channel:manage",
      "support_chat:read",
      "support_chat:message:create"
    ]
  }'
```

### 3. Fetch the token from your app

Provide the SDK with a token callback that fetches from your endpoint. The chat elements call this whenever they need to authenticate, and again automatically when the token expires.

#### React

```typescript
async function getToken() {
  const response = await fetch("/api/chat/token", { method: "POST" });
  const data = await response.json();
  return data.token;
}
```

#### Vanilla JS

```typescript
async function getToken() {
  const response = await fetch("/api/chat/token", { method: "POST" });
  const data = await response.json();
  return data.token;
}
```

#### Swift

```swift
import WhopElements

class WhopAPITokenProvider: WhopTokenProvider {
    private let serverURL = URL(string: "https://your-server.com")!

    func getToken() async -> WhopTokenResponse {
        do {
            var req = URLRequest(url: serverURL.appendingPathComponent("api/chat/token"))
            req.httpMethod = "POST"

            let (data, _) = try await URLSession.shared.data(for: req)
            let json = try JSONSerialization.jsonObject(with: data) as! [String: Any]
            return WhopTokenResponse(accessToken: json["token"] as? String ?? "")
        } catch {
            return WhopTokenResponse(accessToken: "")
        }
    }
}
```

Pass the token provider to the SDK on app launch:

```swift
.task {
    await WhopSDK.configure(tokenProvider: WhopAPITokenProvider())
}
```

### Required scopes

Request these scopes when creating the token:

| Scope                                                  | Purpose         |
| ------------------------------------------------------ | --------------- |
| `chat:message:create`, `chat:read`                     | Channels        |
| `dms:read`, `dms:message:manage`, `dms:channel:manage` | Direct messages |
| `support_chat:read`, `support_chat:message:create`     | Support chats   |

> **Note**
>
> If your app owns the user accounts and mints company-scoped chat tokens, sync those users before passing their `user_id` here. User syncing is not part of OAuth.

#### [Sync your users](/developer/guides/chat/sync-users)

Create or map Whop users before minting company-scoped chat tokens.

## OAuth

OAuth lives on its own page so this guide can stay focused on company-scoped user tokens.

Use OAuth when your app wants users to sign in to Whop themselves through a sign-in page or iOS webview. This is the right choice when your app needs access to a user-owned Whop account, or when you do not want your backend to mint Whop user tokens.

#### [OAuth](/developer/guides/chat/oauth)

Set up OAuth scopes, redirect URIs, web token endpoints, and SDK-managed OAuth on iOS.