登录
Mini App 可以用 Micromeet 账号登录正在使用 Cowork 的人,再从它自己的后端以这个人的身份调用 Micromeet。页面始终拿不到密码、token 或 Mini App 的密钥:Cowork 只给页面一个一次性的 code,由 Mini App 的后端拿它换 token。
只有 Micromeet 签过名、而且至少有一个验证过的服务器域名的已安装 Mini App 能登录(见打包与签名)。内置 Mini App 没有这个模块。
MAESTROSDK.auth.login(params?) 尚未发布
向 Cowork 要一个一次性 code,对应这个 Mini App 和当前登录 Cowork 的人。
参数
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
scopes | string[] | 否 | Mini App 要的权限,例如 ['profile:read']。不传就是 Micromeet 允许这个 Mini App 的全部权限 |
第一次调用时,Cowork 给这个人看一张卡:Mini App 的名字和开发者、它要的权限、将要使用的账号;按钮是 授权 和 取消,默认是取消。卡只出现在这个人正在看的标签页上。授权过一次之后,同样的权限再调用直接拿到 code,不再弹卡。
返回值
Promise<{ ok: true; code: string; region: 'SG' | 'HK' | 'ID'; expiresIn: number } | { ok: false; error: string }>
code 只能用一次,5 分钟内有效(expiresIn 单位为秒)。把 code 和 region 发给你的后端。
error | 含义 |
|---|---|
unsigned | 包没有 Micromeet 的签名,或页面不是已安装的 Mini App |
tampered | 安装后 Mini App 的文件被改过;Cowork 已关闭它 |
host_signed_out | 没有人登录 Cowork,或页面是为另一个账号打开的。如果这正是用户在看的标签页,Cowork 会打开它的登录界面 |
user_cancelled | 用户取消了、标签页在后台,或卡开着时换了账号 |
app_not_available | 这个 AppID 在本区没有登记,或已停用 |
version_not_available | 这个版本没有登记或已停用:请更新 Mini App |
no_server_domain | 这个版本没有验证过的服务器域名,或其中有域名已不再有效(见打包与签名) |
scope_denied | 要了 Micromeet 没允许这个 Mini App 的权限,或 scopes 不是字符串列表 |
rate_limited | 一分钟内要的 code 太多;稍后再试 |
network | Cowork 连不上 Micromeet |
MAESTROSDK.auth.status() 尚未发布
Promise<{ signed: boolean; host: 'cowork'; hostSignedIn: boolean }>。包的签名有效且文件都没被改过时 signed 为 true;有人登录 Cowork 时 hostSignedIn 为 true。可以据此决定是否显示登录按钮。
在 Mini App 的后端
后端保存 Micromeet 登记 AppID 时给的 client secret,Mini App 登记在几个区就有几个;不要放进页面或包里。后端运行在 Mini App 验证过的某个服务器域名上(见打包与签名)。一步步的例子见开发登录 Mini App。
页面发来的请求
页面的 origin 是 miniapp://<appId>。回答它的请求时带上 Access-Control-Allow-Origin: miniapp://<appId>,预检请求(OPTIONS)也要允许它用到的方法和请求头;否则请求在页面里就失败了,到不了你的代码。Micromeet 的 token 留在后端,给页面你自己的会话。
后端工具
@micromeet-ai/miniapp-sdk/server:ESM 和 CommonJS 都能用,需要 Node.js 18 或更新版本。
import { createMiniappAuthClient, MiniappAuthError } from '@micromeet-ai/miniapp-sdk/server';
const auth = createMiniappAuthClient({ appId: 'ai.example.app', clientSecret: process.env.MINIAPP_SECRET_HK });
const tokens = await auth.exchangeCode({ code, region });
const me = await auth.profile({ accessToken: tokens.accessToken, region: tokens.region });| 选项 | 必填 | 说明 |
|---|---|---|
appId | 是 | AppID |
clientSecret | 是 | 这个 client 要调用的那个区的 secret;每个区建一个 client |
coreUrl | 否 | (region) => 地址:调用哪个 Micromeet。默认按区调用正式环境 |
fetch | 否 | 替换全局的 fetch |
timeoutMs | 否 | 每个请求的超时,默认 15000 |
| 函数 | 返回 |
|---|---|
exchangeCode({ code, region }) | token:accessToken、expiresIn(秒)、refreshToken、scope(列表)、user: { ref, name, email }、institution: { iid, name }、region |
refresh({ refreshToken, region }) | 一组新的 token;旧的 refresh token 失效,保存新的 |
revoke({ refreshToken, region }) | 无;让这个人退出 Mini App 的登录 |
profile({ accessToken, region }) | { ref, name, email, institution: { iid, name }, region }(profile:read) |
call({ accessToken, region, path, body? }) | 向接受 Mini App token 的 Micromeet 接口发 POST,返回它的 data |
出错时每个函数都抛出 MiniappAuthError,带 Micromeet 的 code 和 HTTP status(见下面的「错误」)。
Token
| Token | 有效期 | 用途 |
|---|---|---|
| Access token | 15 分钟 | 调用接受 Mini App token 的接口时放在 Authorization: Bearer |
| Refresh token | 30 天 | refresh 换一组新的;每个 refresh token 只能用一次 |
- 之后的每次调用都用 code 带来的那个区;token 只在它的区有效。
- token 代表这个人,以及他登录时在 Cowork 里选中的机构。
user.ref是这个人在这个 Mini App 里的固定编号(换一个 Mini App 就是另一个):用它当你的用户键。- 改密码、退出所有设备、离开机构、版本停用或 Mini App 停用后,token 在下一次请求时失效。
Scope 与接口
| Scope | 接口 | 返回 |
|---|---|---|
profile:read | POST /share/miniapp/profile | { ref, name, email, institution: { iid, name }, region } |
token 只能用在这张表里的接口上,只限这个人授权的 scope,也不会超出这个人在 Micromeet 里本来能做的事。
错误
code | HTTP | 发生了什么 |
|---|---|---|
invalid_client | 401 | 这个区的 AppID 或 secret 不对,或 secret 已被更换 |
invalid_grant | 400 | code 已用过、超过 5 分钟或不是这个 AppID 的;refresh token 已用过、已撤销或超过 30 天;或这个人改了密码、退出了所有设备、离开了机构:重新登录 |
app_not_available | 400 | 这个 Mini App 在这个区已停用 |
version_not_available | 400 | 这个人登录时用的版本已停用:请更新 Mini App |
needLogin | 401 | 调用接口时:access token 过期或已失效。调用 refresh,失败就重新登录 |
forbidden | 403 | 调用接口时:token 没有这个接口的 scope,或这个人在 Micromeet 里不能做这件事 |
network | — | 后端工具连不上 Micromeet(status 为 0) |
params_invalid | 400 或 — | grant_type 不对;或后端工具收到未知的区、不是接口的 path(status 为 0,不发请求) |
HTTP 调用
其他语言的后端做同样的调用。每个都是向 code 所在区的 Micromeet 发 POST,请求体是 JSON:
| 区 | 地址 |
|---|---|
| SG | https://crms-api.micromeet.ai |
| HK | https://crms-api-hk.micromeet.ai |
| ID | https://crms-api-id.micromeet.ai |
| 路径 | 请求体 | 回答里的 data |
|---|---|---|
/miniapp-open/auth/token | { "grant_type": "authorization_code", "app_id", "client_secret", "code" } | { access_token, token_type: "Bearer", expires_in, refresh_token, scope, user: { ref, name, email }, institution: { iid, name }, region };scope 用空格分隔 |
/miniapp-open/auth/token | { "grant_type": "refresh_token", "app_id", "client_secret", "refresh_token" } | 同上 |
/miniapp-open/auth/revoke | { "app_id", "client_secret", "refresh_token" } | { revoked: true } |
/share/miniapp/profile | {},带 Authorization: Bearer <access_token> | { ref, name, email, institution: { iid, name }, region } |
成功时回答 { "code": 0, "success": true, "data": … };失败时回答 { "code": "<错误>", "msg": "…", "success": false },HTTP 状态见上面的「错误」。