跳转到内容

TypeScript SDK

查看 Markdown

TypeScript SDK 拆分为 @sudomimus/* scope 下的小包。只要具体流程适合相应运行时,这些包可用于 Node.js 和浏览器能力足够的运行时。

用途
@sudomimus/connectConnect inquiry 生命周期:establishstatusPollredeeminfo,以及通过应用元数据验 token。
@sudomimus/sessionRefresh token 轮换、introspection、logout、revoke-all,以及 token store 辅助。
@sudomimus/deviceDevice authorization:deviceAuthorizedeviceToken,以及自动轮询辅助。
@sudomimus/nativeSteam ticket 与 AccessKey direct-issue。
jose基于标准的 JWT 解析与密码学验证。

只安装当前集成需要的包:

Terminal window
pnpm add @sudomimus/connect @sudomimus/session
npm install @sudomimus/connect @sudomimus/session
yarn add @sudomimus/connect @sudomimus/session
import { ConnectClient, RETURN_METHOD } from "@sudomimus/connect";
const client = new ConnectClient({
clientAuth: {
applicationAnchor: "your-app-anchor",
privateKeyPem: process.env.SUDOMIMUS_CLIENT_AUTH_PRIVATE_KEY!,
},
});
const inquiry = await client.establish({
applicationAnchor: "your-app-anchor",
returnMethods: [{ type: RETURN_METHOD.STATUS_POLL, payload: {} }],
});
const status = await client.statusPoll({
exposureKey: inquiry.exposureKey,
hiddenKey: inquiry.hiddenKey,
});
if (status.status === "REALIZED") {
const tokens = await client.redeem({
exposureKey: inquiry.exposureKey,
hiddenKey: inquiry.hiddenKey,
confirmationKey: status.confirmationKey,
});
}

/establish 要求 audience 为 sudomimus-connect 的 client-auth JWT。传入 clientAuth 后,SDK 会在内部完成签名。

import {
InMemoryTokenStore,
RotatingSessionClient,
SessionClient,
} from "@sudomimus/session";
const store = new InMemoryTokenStore();
const session = new RotatingSessionClient(new SessionClient(), store);
await session.seed({
accessToken: tokens.accessToken,
refreshToken: tokens.refreshToken,
});
const accessToken = await session.refresh();
await session.logout();

revokeAll 是应用后端操作,需要 audience 为 sudomimus-session 的 client-auth 签名。

import { DeviceClient, DeviceTokenApiError } from "@sudomimus/device";
const device = new DeviceClient({ baseUrl: "https://device-api.sudomimus.com" });
const auth = await device.deviceAuthorize({ applicationAnchor: "your-app-anchor" });
console.log(auth.userCode, auth.verificationUriComplete);
while (true) {
try {
const tokens = await device.deviceToken({ deviceCode: auth.deviceCode });
break;
} catch (error) {
if (
error instanceof DeviceTokenApiError
&& (error.error === "authorization_pending" || error.error === "slow_down")
) {
await new Promise((resolve) => setTimeout(resolve, (error.interval ?? auth.interval) * 1000));
continue;
}
throw error;
}
}

Device authorization 成功后继续使用 @sudomimus/session;Device API 返回的是普通 Sudomimus access/refresh token。

令牌验证与 Connect 解耦。从 Session API 的 GET /applications/{applicationAnchor}/jwks.json 获取应用 JWK Set,按 Cache-Control 缓存,并精确选择 token kid 指定的密钥;遇到未知 kid 时刷新一次。使用 jose 等标准 JOSE 实现解析 JWT 并执行密码学验证,不要再把 Connect /info 当作密钥来源。

验签成功后,从 payload sub 读取应用可见用户键,从 payload sid 读取逻辑会话,从 payload jti 读取 bearer 实例。Access token 不携带个人资料;refresh token 不携带用户标识,并额外包含 rotationVersion。当前资料从 Session /userinfo 获取。离线验证无法观察后续 logout 或权威变化;要求实时会话状态的操作应调用 Session /introspect