# @lingtu/api-key-sdk

仅用于 Node.js 22+ 产品后端。无第三方运行依赖，可独立安装或打包。

```js
import { createApiKeyVerifier } from '@lingtu/api-key-sdk';
const verify = createApiKeyVerifier({
  identityOrigin: process.env.IDENTITY_ORIGIN,
  issuer: process.env.OIDC_ISSUER,
  clientId: process.env.OIDC_CLIENT_ID,
  clientSecret: process.env.OIDC_CLIENT_SECRET,
});
const identity = await verify(apiKey);
// null：凭证无效或未授权。抛错：校验不可用，停止调用，返回503。
// 成功：以 (identity.issuer, identity.sub) 查找本地用户，再检查组织、角色和业务权限。
```

默认超时5000ms，不缓存、不重试、不跟随重定向。生产使用 HTTPS；HTTP 仅允许本机联调。
identityOrigin 是账号服务根地址，issuer 是固定的 OIDC issuer（以 /oauth 结尾），即使使用内部地址访问也不能更改身份 issuer。
产品 client_secret 仅保存在产品后端，不交给 Agent。Agent 只持有用户 API Key。

异常只包含固定错误码，不包含密钥、响应体或底层异常。应用及代理同样必须关闭凭证、请求体和 Authorization 日志。

## 产品后台读取本人密钥元信息（0.2.0）

```js
import { createApiKeyClient } from '@lingtu/api-key-sdk';
const keys = createApiKeyClient({ identityOrigin, issuer, clientId, clientSecret });
const identity = await keys.verify(userApiKey);
// sub 来自本产品已验证的网页登录和本地账号绑定，不采用浏览器传入的 sub。
const page = await keys.metadata(centralSub, { page: 1 });
const selected = await keys.metadata(centralSub, { keyId: selectedKeyId });
```

元信息接口为 POST `/api/client/api-keys/metadata`，应用 Basic 认证，输入 `{sub,page?,keyId?}`。要求用户已关联该应用且应用已开启 API Key 接入。返回 issuer/sub/clientId、page/pageSize/total，以及仅授权当前应用的 keys；每页 20 条。每项只包含 id/name/prefix/active/createdAt/expiresAt/revokedAt/lastVerifiedAt，不返回明文、摘要或其他应用授权。不存在或不属于该用户、未授权该应用的 keyId 返回空列表。

用于产品网页展示密钥与设置本地业务范围，不能代替每次业务请求的 `verify`。产品需另行校验自身网页登录、CSRF、keyId 归属和业务权限。SDK 不创建或撤销用户密钥。

两个工厂均支持可选 `fetcher`，用于可信后端的内部路由或测试；保留原始公共 issuer 的精确核验。使用内部服务时按服务要求保留公共 Host，禁止跟随重定向或记录请求正文。
