@eduwork/dsh-oidc 0.2.4 → 0.3.0-dev.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/README.md +20 -132
  2. package/README_EN.md +20 -177
  3. package/docs/EDUWORK-MIGRATION.en.md +3 -25
  4. package/docs/EDUWORK-MIGRATION.md +3 -25
  5. package/docs/account-extensions.en.md +6 -6
  6. package/docs/account-extensions.md +3 -3
  7. package/docs/architecture.en.md +12 -117
  8. package/docs/architecture.md +12 -118
  9. package/docs/compatibility.en.md +6 -40
  10. package/docs/compatibility.md +6 -40
  11. package/docs/decisions/0001-one-plugin-composition-boundary.en.md +2 -2
  12. package/docs/decisions/0001-one-plugin-composition-boundary.md +2 -2
  13. package/docs/desktop-host.en.md +4 -5
  14. package/docs/desktop-host.md +8 -9
  15. package/docs/development.en.md +2 -2
  16. package/docs/development.md +2 -2
  17. package/docs/dsh-integration.en.md +11 -46
  18. package/docs/dsh-integration.md +12 -47
  19. package/docs/ecnu-reference.en.md +4 -61
  20. package/docs/ecnu-reference.md +4 -61
  21. package/docs/enterprise-profile.en.md +10 -31
  22. package/docs/enterprise-profile.md +11 -32
  23. package/docs/gateway-auth/README.md +168 -0
  24. package/docs/gateway-auth/README_EN.md +70 -0
  25. package/docs/gateway-auth/experimental-oidc-llm.en.md +53 -0
  26. package/docs/gateway-auth/experimental-oidc-llm.md +53 -0
  27. package/docs/gateway-auth/litellm-setup.en.md +114 -0
  28. package/docs/gateway-auth/litellm-setup.md +114 -0
  29. package/docs/gateway-auth/oidc-llm-draft.en.md +141 -0
  30. package/docs/gateway-auth/oidc-llm-draft.md +141 -0
  31. package/docs/getting-started.en.md +17 -122
  32. package/docs/getting-started.md +16 -225
  33. package/docs/key-binding-protocol.en.md +10 -220
  34. package/docs/key-binding-protocol.md +10 -220
  35. package/docs/oidc-interoperability.en.md +1 -1
  36. package/docs/oidc-interoperability.md +1 -1
  37. package/docs/open-integration.en.md +5 -67
  38. package/docs/open-integration.md +5 -67
  39. package/docs/public-resource-protocol.en.md +8 -44
  40. package/docs/public-resource-protocol.md +8 -43
  41. package/docs/security-model.en.md +10 -132
  42. package/docs/security-model.md +10 -132
  43. package/docs/server-integration-contract.en.md +12 -813
  44. package/docs/server-integration-contract.md +12 -825
  45. package/examples/ecnu.enterprise-profile.example.json +14 -19
  46. package/examples/enterprise-profile.example.json +14 -19
  47. package/examples/litellm.enterprise-profile.example.json +9 -0
  48. package/examples/oidc-llm.enterprise-profile.example.json +12 -0
  49. package/examples/resources-discovery.example.json +5 -8
  50. package/lib/callback-page.js +5 -5
  51. package/lib/client.js +31 -48
  52. package/lib/desktop-oidc.js +7 -11
  53. package/lib/gateway-backend.js +443 -0
  54. package/lib/gateway-protocol.js +6 -0
  55. package/lib/index.js +14 -15
  56. package/lib/litellm-protocol.js +117 -0
  57. package/lib/model-resource-transport.js +19 -0
  58. package/lib/oidc-llm-protocol.js +88 -0
  59. package/lib/oidc.js +37 -323
  60. package/lib/profile.js +34 -40
  61. package/lib/provider/authorization-scope.js +46 -0
  62. package/lib/provider/index.js +11 -2
  63. package/lib/typert-schemas.js +1 -1
  64. package/package.json +2 -2
  65. package/protocol/openapi.yaml +33 -240
  66. package/protocol/resources.openapi.yaml +8 -9
  67. package/schema/enterprise-profile.v1alpha1.schema.json +509 -107
@@ -1,237 +1,28 @@
1
- # 接入指南:把企业 OIDC 与模型服务接入 DSH
1
+ # 接入指南
2
2
 
3
3
  **简体中文** | [English](getting-started.en.md)
4
4
 
5
- 这份指南面向准备在自己机构部署 `dsh-oidc` 的管理员和开发者。完成后,用户可以在普通 DSH Web 中:
5
+ 新客户端的机构模型请求使用登录获得的 Access Token。先选择服务端实际提供的契约,再配置完整发现地址。
6
6
 
7
- 1. 使用机构 OIDC 登录;
8
- 2. 明确确认创建或绑定模型运行凭据;
9
- 3. 在“企业服务”设置页查看账号、Provider 和模型;
10
- 4. 直接选择企业模型开始对话;
11
- 5. 刷新登录、检查连接或退出登录,而模型 API Key 不进入浏览器配置。
12
-
13
- `dsh-oidc` 不要求 Wails,也不要求使用 ChatECNU Work。华东师范大学只是参考实现。
14
-
15
- ## 1. 先确认你需要准备什么
16
-
17
- | 组件 | 谁提供 | 最低要求 |
7
+ | 服务 | 示例 | 注册方式 |
18
8
  | --- | --- | --- |
19
- | DSH Host | 部署方 | 本版基线 DeepSeek Harness `0.1.5-rc.1`,Node.js 22+;不要与历史稳定包混用。 |
20
- | 机构企业模型集成服务 | 同一服务所有者 | 纯身份档提供 OIDC;托管模型档再联合提供固定 Key Binding 与 OpenAI-compatible 模型网关。 |
21
- | Enterprise Profile | 部署方 | 一份受信任的本地 JSON,只存公开配置,不存密钥或个人信息。 |
22
- | Credential Provider | DSH Host | 当前 Web backend 仅支持可信单用户本机存储。 |
23
-
24
- 先把[服务端接口规范](server-integration-contract.md)交给身份平台与模型平台共同确认。只有 OIDC 时,插件只能证明“用户是谁”;没有 Key Binding 和模型网关,就无法安全完成“这个用户可以调用哪些企业模型”的闭环。不要把全局模型 API Key 写进 Enterprise Profile。
25
-
26
- ## 2. 注册 OIDC Public Client
27
-
28
- 在机构身份平台登记一个不带 Client Secret 的 Public Client。回调地址必须逐字符匹配:
29
-
30
- ```text
31
- http://127.0.0.1:3080/oauth/callback
32
- ```
33
-
34
- 以下固定端口用于本机 Web 验证。新桌面默认临时随机端口,固定端口 IdP 的配置方法见 [桌面宿主接入](desktop-host.md)。`127.0.0.1` 和 `/oauth/callback` 固定不可配置。`3080` 是推荐的 DSH 端口;若修改 DSH WebServer 端口,OIDC 注册值必须使用相同端口。不要登记 `localhost`、局域网地址或公网地址。
35
-
36
- OIDC Provider 必须通过 Discovery 发布 `authorization_endpoint`、`token_endpoint`、`jwks_uri` 和 `userinfo_endpoint`,支持 PKCE `S256`,并返回:
37
-
38
- - ID Token:至少包含正确的 `iss`、`aud`、`sub`、`iat`、`exp` 和 `nonce`;当前版本只支持带 `kid` 的 RS256;
39
- - UserInfo:必须包含与 ID Token 相同的非空 `sub`;建议提供标准 `name` 作为用户显示名;
40
- - Access Token:可以是 JWT 或 opaque token,但 Key Binding 服务必须能验证 issuer、audience、有效期、scope 和 subject。
41
-
42
- 插件只读取标准 `userinfo.name`,缺失时显示 `userinfo.sub`。它不会读取私有人员接口,也不支持 JSON Path 姓名映射。完整兼容要求见 [OIDC 兼容规范](oidc-interoperability.md)。
43
-
44
- ## 3. 实现完整机构服务端
45
-
46
- 本节针对托管企业模型能力:需要上一节的 OIDC、下面的 Key Binding,以及接受绑定凭据的 OpenAI-compatible 模型网关。纯身份档可跳过本节。它们可以由内部不同系统承载,但必须有统一的版本、安全和运维责任。接口定义见[服务端接口规范](server-integration-contract.md)。
47
-
48
- Key Binding 不是 OIDC 标准的一部分,而是 `dsh-oidc` 定义的企业模型凭据协议。Enterprise Profile 用 `baseURL` 指定接口组基址,插件固定调用:
49
-
50
- ```text
51
- GET {baseURL}/bootstrap
52
- POST {baseURL}/runtime-credential/provision
53
- POST {baseURL}/runtime-credential/resolve
54
- POST {baseURL}/runtime-credential/renew
55
- ```
56
-
57
- Profile 还可以用可选的 `keyBinding.credentialRef` 隔离本地 DSH Credential Provider 中的秘密条目。它不参与网络请求,也不改变下列接口;默认统一为 `EDUWORK_API_KEY`,也接受同名显式配置;只有需要独立管理的自定义引用才另行指定。旧自动名称兼容迁移和身份归属校验见 [Profile 规范](enterprise-profile.md)。
58
-
59
- 每个请求都携带 OIDC Access Token:
60
-
61
- ```http
62
- Authorization: Bearer <oidc-access-token>
63
- ```
64
-
65
- 服务端必须验证 Access Token 和用户授权,不得只相信请求里的 `provider_id`。`provision` 与 `renew` 还必须支持 `Idempotency-Key`。返回的 `api_key` 只能通过 TLS 响应一次性交给插件,必须带 `Cache-Control: no-store`,不得进入日志、监控标签或错误详情。
66
-
67
- 规范文本见 [Key Binding 协议](key-binding-protocol.md),可直接交给后端研发的机器可读契约是 [`protocol/openapi.yaml`](../protocol/openapi.yaml)。OIDC 和模型网关分别遵循其既有标准,因此本项目不复制另一份 OpenAPI。
68
-
69
- ## 4. 创建 Enterprise Profile
70
-
71
- 复制 [`examples/enterprise-profile.example.json`](../examples/enterprise-profile.example.json),至少替换:
72
-
73
- - `id`、`displayName`、`organization`;
74
- - `brand` 中有权使用的名称、颜色和支持地址;
75
- - `oidc.issuer`、Public `clientId` 与 scopes;
76
- - `keyBinding.baseURL`;
77
- - 跨环境需要隔离本地 Key 时,可选配置 `keyBinding.credentialRef`;
78
- - `provider.id`、OpenAI-compatible `baseURL` 和模型列表。
79
-
80
- 典型结构如下:
81
-
82
- ```json
83
- {
84
- "schemaVersion": "dsh-oidc/v1alpha1",
85
- "id": "example-university",
86
- "displayName": "Example University AI",
87
- "organization": "Example University",
88
- "brand": {
89
- "productName": "Example AI Work",
90
- "organizationName": "Example University",
91
- "mark": "E",
92
- "primaryColor": "#5157af",
93
- "loginTitle": "使用机构账号登录",
94
- "loginDescription": "登录后绑定企业模型运行凭据。",
95
- "supportURL": "https://support.example.edu/ai"
96
- },
97
- "oidc": {
98
- "issuer": "https://id.example.edu/oidc",
99
- "clientId": "dsh-web-public-client",
100
- "scopes": ["openid", "profile", "offline_access"]
101
- },
102
- "keyBinding": {
103
- "baseURL": "https://ai.example.edu/api/worker/v1"
104
- },
105
- "provider": {
106
- "id": "example-ai",
107
- "displayName": "Example AI",
108
- "adapter": "openai-compatible",
109
- "baseURL": "https://ai.example.edu/open/api/v1",
110
- "models": [
111
- { "id": "example-max", "name": "Example Max", "input": ["text"] },
112
- { "id": "example-plus", "name": "Example Plus", "input": ["text", "image"] }
113
- ]
114
- }
115
- }
116
- ```
117
-
118
- Profile 是部署配置,不是用户输入。它可以声明模型事实和有限品牌 token,但不能加载脚本、CSS、工具、Skill 或远程 Provider adapter。字段全集和安全限制见 [Enterprise Profile 规范](enterprise-profile.md)。
119
-
120
- ## 5. 安装到本机 DSH Web
121
-
122
- 本版采用精确的 `0.2.0` 与统一 DSH `0.1.5-rc.1`。发布状态以 npm registry 为准;若准备期间尚未发布,使用本地冻结候选或下方源码方式,不混装旧 DSH 依赖。
123
-
124
- `dsh-oidc` 本身是可直接安装的 DSH Bundle。团队部署应从 npm 安装经过复核的精确版本:
125
-
126
- ```bash
127
- dsh plugin --profile web add @eduwork/dsh-oidc@0.2.0
128
- ```
129
-
130
- 需要审计、开发或测试尚未发布的改动时,再从本地 checkout 安装:
131
-
132
- ```bash
133
- git clone https://github.com/ecnu/EduWork.git
134
- cd EduWork/packages/dsh-oidc
135
- npm ci
136
- npm run check
137
- dsh plugin --profile web add .
138
- ```
139
-
140
- 也可以在项目父目录中显式传入相对路径:
141
-
142
- ```bash
143
- dsh plugin --profile web add ./EduWork/packages/dsh-oidc
144
- ```
145
-
146
- DSH 会把本地 checkout 链接到 `$DSH_HOME/profiles/web`,不会扫描或复制当前目录;安装完成后不要移动或删除 checkout。源码部署应固定经过审核的 commit。生产或团队 Profile 应使用精确 npm 版本,不要混装其他 DSH 预发布线。
147
-
148
- 设置 Enterprise Profile 路径,并让 DSH 监听固定 loopback host:
149
-
150
- ```bash
151
- export EDUWORK_OIDC_PROFILE=/etc/dsh/enterprise-profile.json
152
- dsh --profile web --host 127.0.0.1 --port 3080 --no-open
153
- ```
154
-
155
- PowerShell 示例:
156
-
157
- ```powershell
158
- $env:EDUWORK_OIDC_PROFILE = 'C:\dsh-config\enterprise-profile.json'
159
- dsh --profile web --host 127.0.0.1 --port 3080 --no-open
160
- ```
161
-
162
- 插件会从 DSH WebServer 的端口构造 `http://127.0.0.1:<port>/oauth/callback`,不接受 `publicBaseURL`,也不会从代理 header 推断地址。若启动参数改变端口,必须同步修改 OIDC Public Client 的登记值。
163
-
164
- 安装命令会把 `dsh-oidc` 作为 Bundle 加到 Profile,并由包内 `cordis.patch.yml` 挂载插件。它不会遍历当前工作目录,也不会替换 DSH 的 Web、会话、Workspace、LLM、Credential Provider 或其他官方能力;当前目录只用于解析 `.`、`./EduWork/packages/dsh-oidc` 等相对安装路径。
165
-
166
- ## 6. 高级组合:自定义 Bundle 或桌面宿主
167
-
168
- 如果产品已有自己的 Bundle,可以不使用包内默认 patch,而是在产品 patch 中显式插入:
169
-
170
- ```yaml
171
- - insert:
172
- - id: enterprise-oidc
173
- name: '@eduwork/dsh-oidc'
174
- config:
175
- profilePathEnv: EDUWORK_OIDC_PROFILE
176
- web:
177
- returnPath: /
178
- ```
179
-
180
- 仅为兼容旧宿主,仍保留以下 native backend 示例:
181
-
182
- ```yaml
183
- - insert:
184
- - id: enterprise-oidc
185
- name: '@eduwork/dsh-oidc'
186
- config:
187
- backend: native
188
- uiMode: models-only
189
- profilePathEnv: PRODUCT_ENTERPRISE_PROFILE
190
- ```
191
-
192
- 上面是旧版 `native` 桥接示例;新 Wails/Electron 组合应使用 `backend: desktop`,共用临时 loopback 回调与官方 `nativeCommand`,无需另写认证桥。见 [桌面 Host 集成](desktop-host.md)。旧 native backend 必须提供 `enterpriseAccounts` 服务,并与 Web 一样传入标准 Enterprise Profile。产品自有目录、租户或账号配置必须先由产品装配层转换为该 Profile,不能交给 `dsh-oidc` 解释。宿主可以由 Wails、Electron、Tauri 或其他技术实现;插件本身不依赖任何桌面框架或产品目录格式。接口和能力探测见 [DSH 集成说明](dsh-integration.md)。
193
-
194
- ## 7. 上线前验收
195
-
196
- 至少完成以下真实链路:
197
-
198
- 1. `dsh --profile web --dump-config` 中只有一个 `enterprise-oidc` 实例;
199
- 2. 登录跳转和 `/oauth/callback` 成功,错误 state、重复参数和过期 code 会失败;
200
- 3. 设置页显示标准 UserInfo `name`,没有 `name` 时显示稳定 `sub`;
201
- 4. 未创建运行凭据时先显示用户确认,不自动静默 provision;
202
- 5. provision/resolve 后企业模型可完成流式对话;
203
- 6. API Key 不出现在 Profile、浏览器配置、日志和导出的会话中;
204
- 7. refresh、过期、撤销、权限不足、限流和 Key Binding 不可用均有可理解的失败结果;
205
- 8. logout 清理本地 OIDC 会话和模型凭据,并尽力调用标准 revocation endpoint;
206
- 9. DSH WebServer 只监听 `127.0.0.1`,没有通过反向代理或端口映射暴露为共享站点;
207
- 10. OIDC、全部四个 Key Binding 操作和模型网关按[服务端接口规范](server-integration-contract.md)联合通过验收。
208
-
209
- 当前 Web backend 不支持共享 Web。需要共享场景时必须由具备每用户隔离的新宿主 backend 承担,不能直接放宽 loopback 约束。详见 [安全模型](security-model.md) 和 [公开发布检查表](release-checklist.md)。
210
-
211
- ## 8. 常见问题
212
-
213
- ### 回调失败或跳回后仍未登录
214
-
215
- 核对 OIDC 注册值是否与 `http://127.0.0.1:<DSH端口>/oauth/callback` 完全一致。确认 DSH 实际监听 host 为 `127.0.0.1`,登记端口与启动端口相同;不要使用 `localhost`、局域网地址或公网地址。
216
-
217
- ### 页面显示一串 subject,而不是姓名
218
-
219
- 这是标准降级行为。让 OIDC UserInfo 在 `profile` scope 下返回非空标准 `name`,并保证 `sub` 与 ID Token 完全一致。
220
-
221
- ### 登录成功但模型不可用
9
+ | LiteLLM native contract 1 | [LiteLLM](../examples/litellm.enterprise-profile.example.json) | 按契约动态注册 |
10
+ | oidc-llm 0.1 实验 | [OIDC Token](../examples/oidc-llm.enterprise-profile.example.json) | 预注册 public client,显式选择 oidc 或 oauth |
11
+ | 仅标准 OIDC 身份 | [纯身份](../examples/identity-only.example.json) | 预注册 public client,不提供企业模型 |
222
12
 
223
- 检查 Key Binding 的 `/bootstrap` 状态、用户是否确认 provision、返回的 `provider_id` 是否等于 Enterprise Profile 的 `provider.id`,以及模型网关是否接受绑定后的 API Key。
13
+ OIDC 模式需要浏览器登录、Code + PKCE、有效 ID Token 和 UserInfo。服务端必须明确授权该 Access Token 调用模型;仅填一个模型 URL 不会赋予权限。详见[服务端契约](server-integration-contract.md)。
224
14
 
225
- ### 模型支持 thinking,但不支持 reasoning effort
15
+ ## Host 配置
226
16
 
227
- 在模型 `compat` 中设置:
17
+ 插件通过 config.profile、config.profiles 或 EDUWORK_OIDC_PROFILE 指向的可信 JSON 文件加载配置。桌面使用 backend: desktop,Host 提供凭据存储和 desktopServices.openExternal;插件监听临时 127.0.0.1 回调。本机 Web 使用 backend: web,WebServer 必须监听 127.0.0.1,回调端口取实际服务端口。
228
18
 
229
- ```json
230
- { "supportsReasoningEffort": false }
231
- ```
19
+ 仅用于包含本分支源码的开发装配,尚未发布。按[开发说明](development.md)构建和验证。正式装配应固定通过审查的已发布包,不能把新配置直接交给尚不支持它的旧版本。
232
20
 
233
- 插件会保留 thinking 行为并移除不受支持的 effort 参数,不会因此拒绝调用。
21
+ ## 登录与使用
234
22
 
235
- ### 企业服务设置在哪里
23
+ 1. 用户在浏览器完成授权,客户端校验 state、PKCE 及适用的身份信息。
24
+ 2. 登录后自动获取模型目录,使用同一授权连接 DSH Provider,不再要求创建模型 Key。
25
+ 3. 临近到期时自动刷新,刷新后保留原身份和授权上下文。
26
+ 4. 退出清理本地状态,停止使用旧授权。Token 的服务端寿命按部署策略执行。
236
27
 
237
- 插件通过官方 `settings.models.footer` 插槽显示已配置机构,保留官方“模型”设置页和个人 API Key。机构配置来自发行方的可信文件;产品可以提供打开配置文件的入口,插件不提供任意创建或修改机构端点的表单。
28
+ 配额继续由机构扩展提供,见[账户扩展](account-extensions.md)。旧配置请按[迁移说明](key-binding-protocol.md)改为 Token 接入。配置和日志不得包含密码、client secret 或用户 Token。
@@ -1,227 +1,17 @@
1
- # Worker User Center Key Binding Protocol v1
1
+ # Migrating legacy Key Binding
2
2
 
3
3
  [简体中文](key-binding-protocol.md) | **English**
4
4
 
5
- ## 1. Status and terminology
5
+ The current client source removes Key Binding: it no longer calls /bootstrap or /runtime-credential provision, resolve or renew, and rejects keyBinding profiles and the old backend: native account bridge.
6
6
 
7
- This document defines `worker-user-center-v1`, the enterprise management protocol used by `dsh-oidc` to bind an OIDC-authenticated subject to a model runtime API key. It is not part of OIDC.
7
+ Servers may keep legacy endpoints for already released clients. New clients use Access Tokens for organization models; server compatibility does not require preserving the old client model-key path.
8
8
 
9
- It is part of the managed-model tier of the [server API specification](server-integration-contract.en.md), delivered together with the OIDC Provider and model gateway. Identity-only Profiles do not require Key Binding.
9
+ ## Migration
10
10
 
11
- The key words **MUST**, **MUST NOT**, **REQUIRED**, **SHALL**, **SHALL NOT**, **SHOULD**, **SHOULD NOT**, **RECOMMENDED**, **NOT RECOMMENDED**, **MAY**, and **OPTIONAL** are interpreted as described by RFC 2119 and RFC 8174.
11
+ 1. Confirm [experimental oidc-llm](gateway-auth/experimental-oidc-llm.en.md) or [LiteLLM native](gateway-auth/README_EN.md) server support.
12
+ 2. Replace oidc + keyBinding + provider.baseURL with a full auth.discoveryUrl. OIDC additionally requires the explicit experimental flag, registered public client ID and identityMode.
13
+ 3. Preserve stable profile/provider IDs and reviewed model metadata. Validated discovery and catalog responses determine API endpoints and model visibility.
14
+ 4. Sign in again. The client neither guesses a new discovery URL nor treats saved model keys as Access Tokens, and never silently falls back. It does not read old model keys or bulk-delete keys potentially used elsewhere.
15
+ 5. Identity-only oidc profiles may remain but cannot include a model provider.
12
16
 
13
- [`protocol/openapi.yaml`](../protocol/openapi.yaml) is the machine-readable companion contract. If prose and OpenAPI differ, this document controls security and lifecycle semantics; OpenAPI controls field spelling and basic shapes. Such a difference is a specification defect and must be reported.
14
-
15
- ## 2. Design objectives
16
-
17
- The protocol separates three credentials:
18
-
19
- - the user's organization password, seen only by the OIDC Provider;
20
- - an OIDC access token, used only against the UserInfo and Key Binding services;
21
- - a model runtime API key, used only by the model Provider route.
22
-
23
- The API key is a replaceable, revocable runtime credential—not proof of the user's identity. The Key Binding server is the authorization authority for provisioning and resolving it.
24
-
25
- ## 3. Base URL and fixed resources
26
-
27
- An Enterprise Profile supplies one HTTPS `keyBinding.baseURL`. It MUST NOT contain userinfo, query, or fragment and SHOULD contain a versioned path such as `/api/worker/v1`.
28
-
29
- The following paths are fixed relative to that base URL:
30
-
31
- | Method | Path | Purpose |
32
- | --- | --- | --- |
33
- | GET | `/bootstrap` | Read Provider, capabilities, entitlement, and credential state. |
34
- | POST | `/runtime-credential/provision` | Create/bind a credential when state is `missing`. |
35
- | POST | `/runtime-credential/resolve` | Return the active credential. |
36
- | POST | `/runtime-credential/renew` | Rotate an `expiring` or `expired` credential. |
37
-
38
- Profiles and users MUST NOT override paths, HTTP methods, field mappings, or credential-reference names.
39
-
40
- ## 4. Authentication and authorization
41
-
42
- Every request MUST use TLS except explicit loopback development. The client sends:
43
-
44
- ```http
45
- Authorization: Bearer <OIDC access token>
46
- Accept: application/json
47
- ```
48
-
49
- The server MUST validate at least:
50
-
51
- - token signature or introspection result;
52
- - issuer;
53
- - audience intended for the Key Binding service;
54
- - expiry/not-before;
55
- - authenticated subject;
56
- - required operation scope;
57
- - organization membership, account state, and model entitlement.
58
-
59
- Recommended scopes are:
60
-
61
- | Operation | Scope |
62
- | --- | --- |
63
- | bootstrap | `worker.bootstrap.read` |
64
- | provision | `worker.credential.provision` |
65
- | resolve | `worker.credential.read` |
66
- | renew | `worker.credential.renew` |
67
-
68
- A deployment MAY use different scope names, but they remain OIDC authorization policy and are listed in the Enterprise Profile `oidc.scopes`; wire operations do not change.
69
-
70
- The server MUST derive the bound subject from the validated access token. It MUST NOT accept a caller-supplied subject ID in a request body.
71
-
72
- ## 5. Bootstrap
73
-
74
- Request:
75
-
76
- ```http
77
- GET /api/worker/v1/bootstrap HTTP/1.1
78
- Authorization: Bearer …
79
- Accept: application/json
80
- ```
81
-
82
- Minimum successful response:
83
-
84
- ```json
85
- {
86
- "provider": { "id": "example-ai" },
87
- "capabilities": ["worker.credential.provision"],
88
- "runtime_credential": {
89
- "status": "missing",
90
- "provisioning": { "allowed": true }
91
- }
92
- }
93
- ```
94
-
95
- The returned `provider.id` is REQUIRED and MUST exactly equal the Enterprise Profile `provider.id`. A mismatch is a binding failure.
96
-
97
- Valid `runtime_credential.status` values are:
98
-
99
- - `missing`: no credential is bound;
100
- - `active`: an active credential can be resolved;
101
- - `expiring`: rotate if `api_key_id` exists, otherwise resolve according to server policy;
102
- - `expired`: rotate if `api_key_id` exists, otherwise resolve according to server policy;
103
- - `suspended`: entitlement/account disabled; local credential must not be treated as usable;
104
- - `unavailable`: service cannot currently provide a credential.
105
-
106
- `subject` MAY carry informational management-plane display data. The client MUST NOT use it to replace OIDC `sub` or `name`.
107
-
108
- `protocol_version`, if present, MUST be `worker.user-center.v1`, `worker-user-center/v1` or `eduwork-resources/v1` (aliases of the same v1 wire; unknown versions are rejected). It is optional during v1 adoption; a future major protocol can require explicit negotiation.
109
-
110
- ## 6. Provision
111
-
112
- The user MUST complete OIDC authentication before provisioning. `dsh-oidc` additionally requires an explicit UI action (`allowProvision: true`) so a callback alone does not silently create a model credential.
113
-
114
- ```http
115
- POST /api/worker/v1/runtime-credential/provision HTTP/1.1
116
- Authorization: Bearer …
117
- Content-Type: application/json
118
- Idempotency-Key: <UUID>
119
-
120
- { "provider_id": "example-ai" }
121
- ```
122
-
123
- The server MUST:
124
-
125
- - verify `provider_id` is authorized for the subject;
126
- - enforce organization provisioning policy;
127
- - make the operation idempotent for the same authenticated subject, Provider, and Idempotency-Key;
128
- - return the same logical result for a replay during the server's idempotency retention window;
129
- - reject reuse of a key with a different payload as `409 Conflict`;
130
- - never log the returned API key.
131
-
132
- ## 7. Resolve
133
-
134
- ```http
135
- POST /api/worker/v1/runtime-credential/resolve HTTP/1.1
136
- Authorization: Bearer …
137
- Content-Type: application/json
138
-
139
- {
140
- "provider_id": "example-ai",
141
- "api_key_id": "optional-known-id"
142
- }
143
- ```
144
-
145
- Resolve MUST NOT create a new entitlement. It returns the active credential already bound to the subject or a `404`/policy error. A server MAY rotate opaque secret material while preserving the same logical `api_key_id`, but it must not change Provider ownership.
146
-
147
- ## 8. Renew
148
-
149
- ```http
150
- POST /api/worker/v1/runtime-credential/renew HTTP/1.1
151
- Authorization: Bearer …
152
- Content-Type: application/json
153
- Idempotency-Key: <UUID>
154
-
155
- {
156
- "provider_id": "example-ai",
157
- "api_key_id": "key-123"
158
- }
159
- ```
160
-
161
- Renew requires `api_key_id`, is idempotent, and rotates or replaces an expiring/expired credential. The server SHOULD invalidate superseded secret material as soon as operationally safe and MUST document any overlap window.
162
-
163
- ## 9. Credential response
164
-
165
- All three successful POST operations return:
166
-
167
- ```json
168
- {
169
- "provider_id": "example-ai",
170
- "api_key": "secret-runtime-value",
171
- "api_key_id": "key-123",
172
- "status": "active",
173
- "expires_at": "2026-09-01T00:00:00Z"
174
- }
175
- ```
176
-
177
- `provider_id`, `api_key`, and `status=active` are REQUIRED. The client refuses an absent/mismatched Provider or empty key.
178
-
179
- Credential responses MUST include `Cache-Control: no-store` and SHOULD include `Pragma: no-cache`. Servers, proxies, APM agents, and WAFs MUST redact Authorization headers and `api_key` response fields. The secret MUST NOT be placed in URLs, error details, analytics events, or audit logs.
180
-
181
- ## 10. Errors
182
-
183
- Errors SHOULD use `application/problem+json` following RFC 9457 with a stable extension field `code`. At minimum:
184
-
185
- - `400`: malformed request/Provider ID;
186
- - `401`: missing, invalid, expired, or wrong-audience token;
187
- - `403`: scope, membership, entitlement, suspension, or provisioning policy denial;
188
- - `404`: no resolvable/renewable credential;
189
- - `409`: idempotency or lifecycle conflict;
190
- - `429`: rate limit, preferably with `Retry-After`;
191
- - `5xx`: server failure without secret material.
192
-
193
- Clients MUST NOT retry provisioning/renewal without preserving the same Idempotency-Key for the same logical operation. `dsh-oidc` currently performs one call; DSH model request retries are separate and never repeat Key Binding operations.
194
-
195
- ## 11. Lifecycle and revocation
196
-
197
- The Key Binding service SHOULD revoke model credentials when:
198
-
199
- - organization membership or entitlement ends;
200
- - the OIDC subject is disabled;
201
- - a credential is rotated;
202
- - a security administrator revokes it;
203
- - its maximum lifetime expires.
204
-
205
- Local logout removes the cached model key but does not by itself prove remote revocation. Deployments requiring immediate remote revocation SHOULD add an authenticated management operation in a future protocol version rather than overloading OIDC token revocation.
206
-
207
- The model gateway MUST independently enforce API key status, Provider scope, expiration, and quota. Possession of an old key must not bypass the current enterprise policy indefinitely.
208
-
209
- ## 12. Privacy and audit
210
-
211
- The server SHOULD minimize identity data in bootstrap. Audit records SHOULD contain event time, opaque subject reference, Provider ID, operation, outcome, policy reason, request correlation ID, and `api_key_id`—never the API key or OIDC token.
212
-
213
- Retention, access control, breach response, and cross-border processing are deployment responsibilities. The protocol does not grant permission to collect additional personal data.
214
-
215
- ## 13. Conformance checklist
216
-
217
- A server is conformant when it:
218
-
219
- - implements all four fixed resources;
220
- - authenticates requests with the OIDC access token and never request-body subject data;
221
- - returns exact Provider binding;
222
- - enforces required scopes and organization entitlement;
223
- - implements provision/renew idempotency;
224
- - returns no-store credential responses;
225
- - never logs secrets;
226
- - exposes stable lifecycle states and problem codes;
227
- - passes the repository's OpenAPI contract tests plus organization-specific authorization tests.
17
+ This is a breaking configuration change in unpublished source. Consult historical versions for the retired protocol. Personal API-key settings remain available.