会话令牌 (Sessions)
会话令牌 (Session Token) 是交给你的用户端(浏览器、小程序、App)的短时凭据:它代表某一个成员,只能以这个成员的身份和 Agent 对话。 工作区 API Key 留在你的后端,客户端永远只拿会话令牌。
你的后端(持有 sk_…) 你的客户端
┌───────────────────────────┐ token ┌───────────────────────────────┐
│ 1. 认证你自己的用户 │ ────────▶ │ 3. new OpenhexClient({ apiKey: │
│ 2. startVisitorSession / │ │ token }) 或 <ChatWidget │
│ mintSession 换令牌 │ │ getToken={…} /> │
└───────────────────────────┘ └───────────────────────────────┘
本页示例都基于一个绑定了 slug 的工作区句柄:
import { OpenhexClient } from '@openhex-ai/agent-sdk';
const ws = new OpenhexClient({ apiKey: process.env.OPENHEX_WORKSPACE_KEY! })
.workspace(process.env.OPENHEX_WORKSPACE_SLUG!);
一步到位:startVisitorSession
绝大多数集成只需要这一个方法:它先按 sp_user_ref 幂等开通成员,再为他签发令牌。
const { token, user_id, expires_at } = await ws.startVisitorSession({
sp_user_ref: `web_${visitorId}`, // 稳定引用:同一个人 → 同一个成员 → 同一段对话
display_name: '网站访客', // 可选
ttl_seconds: 1800, // 可选,默认 3600,最长 86400
});
它等价于依次调用 provisionMember 和 mintSession(两次 HTTP 请求)。sp_user_ref 一定要稳定:匿名访客用 httpOnly cookie 里的随机值,登录用户用你的用户 id,小程序用 openid。引用一变,平台就当成一个新成员,历史对话也就找不回来了。
为已开通的成员签发:mintSession
成员已经开通过(例如注册时调过 provisionMember),之后每次登录只需要签发:
const session = await ws.mintSession({
sp_user_ref: 'user-42',
ttl_seconds: 3600,
});
// → { token, user_id, expires_at }
| 参数 | 类型 | 说明 |
|---|---|---|
sp_user_ref | string | 已开通成员的引用 |
ttl_seconds | number? | 有效期(秒)。不传为 3600,最大 86400 |
| 返回字段 | 说明 |
|---|---|
token | 会话令牌(JWT),交给客户端 |
user_id | 成员 id |
expires_at | 过期时间(ISO-8601 字符串) |
在客户端使用令牌
令牌就是一个 Bearer 凭据,直接当作 apiKey 传给 SDK:
const client = new OpenhexClient({ apiKey: token, agentId: '你的-agent-id' });
const turn = await client.sendMessage('你好');
在 React 里交给组件的 getToken,组件会在每次请求前调用它,令牌快过期时自动换新:
<ChatWidget agentId="你的-agent-id" getToken={fetchTokenFromYourBackend} persist />
完整的前后端示例见示例:网站客服组件。
会话令牌能做什么、不能做什么:
| 能 | 不能 |
|---|---|
| 以该成员身份和 Agent 对话、上传附件、读取对话历史 | 调用任何需要工作区 API Key 的方法(listAgents 返回 403) |
读取单个 Agent 的公开信息(GET /api/v2/marketplace/agents/{agentId}) | 以所有者身份训练 Agent |
有效期怎么定
- 越短越安全。 令牌泄漏后在过期前一直可用;停用成员也不会吊销已经签发的令牌。
- 靠续期而不是长有效期来保证体验。 组件的
getToken会自动换新,你的签发接口只需要做好限流(按 IP / cookie)。 - 网页客服这类匿名场景常用 1800 秒;已登录用户可以放宽到数小时。
公开短信注册(无需鉴权)
如果你没有自己的用户体系,可以让用户用手机号 + 验证码直接成为工作区成员。这两个接口不需要任何密钥,可以从客户端直接调用,但要求工作区开启了公开短信注册。
// 客户端也要传一个 apiKey 占位——SDK 构造时需要它,这两个接口会忽略它
const pub = new OpenhexClient({ apiKey: 'public' });
await pub.workspaces.sendSmsCode('your-workspace', { phone: '13800000000' });
const session = await pub.workspaces.verifySmsCode('your-workspace', {
phone: '13800000000',
code: '123456',
});
// → { token, user_id, expires_at },首次验证会自动开通成员
不带国家码的 11 位大陆手机号会按 +86 处理,同一个号码始终对应同一个成员。
| 接口 | 状态码 | 含义 |
|---|---|---|
sendSmsCode | 204 | 验证码已发送 |
400 | 手机号格式不对(例如少于 7 位) | |
403 | 该工作区没有开启公开短信注册 | |
404 | 工作区不存在或未启用 | |
verifySmsCode | 200 | 验证通过,返回会话令牌 |
401 | invalid_or_expired_code:验证码错误或已过期 |
常见错误
| 状态码 | message | 原因 |
|---|---|---|
400 | body/ttl_seconds Number must be less than or equal to 86400 | 有效期超过上限 |
401 | workspace API key required | 签发会话只接受工作区 API Key |
403 | member status is suspended | 成员已被停用 |
404 | member not found for sp_user_ref | mintSession 前没有开通这个成员(改用 startVisitorSession) |