@eduwork/dsh-oidc 0.2.4 → 0.3.0-dev.2
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.
- package/CHANGELOG.en.md +6 -0
- package/CHANGELOG.md +6 -0
- package/README.md +20 -132
- package/README_EN.md +20 -177
- package/docs/EDUWORK-MIGRATION.en.md +3 -25
- package/docs/EDUWORK-MIGRATION.md +3 -25
- package/docs/account-extensions.en.md +6 -6
- package/docs/account-extensions.md +3 -3
- package/docs/architecture.en.md +12 -117
- package/docs/architecture.md +12 -118
- package/docs/compatibility.en.md +6 -40
- package/docs/compatibility.md +6 -40
- package/docs/decisions/0001-one-plugin-composition-boundary.en.md +2 -2
- package/docs/decisions/0001-one-plugin-composition-boundary.md +2 -2
- package/docs/desktop-host.en.md +4 -5
- package/docs/desktop-host.md +8 -9
- package/docs/development.en.md +2 -2
- package/docs/development.md +2 -2
- package/docs/dsh-integration.en.md +11 -46
- package/docs/dsh-integration.md +12 -47
- package/docs/ecnu-reference.en.md +4 -61
- package/docs/ecnu-reference.md +4 -61
- package/docs/enterprise-profile.en.md +11 -32
- package/docs/enterprise-profile.md +12 -33
- package/docs/gateway-auth/README.md +168 -0
- package/docs/gateway-auth/README_EN.md +70 -0
- package/docs/gateway-auth/experimental-oidc-llm.en.md +53 -0
- package/docs/gateway-auth/experimental-oidc-llm.md +53 -0
- package/docs/gateway-auth/litellm-setup.en.md +114 -0
- package/docs/gateway-auth/litellm-setup.md +114 -0
- package/docs/gateway-auth/oidc-llm-draft.en.md +141 -0
- package/docs/gateway-auth/oidc-llm-draft.md +141 -0
- package/docs/getting-started.en.md +17 -122
- package/docs/getting-started.md +16 -225
- package/docs/key-binding-protocol.en.md +10 -220
- package/docs/key-binding-protocol.md +10 -220
- package/docs/oidc-interoperability.en.md +1 -1
- package/docs/oidc-interoperability.md +1 -1
- package/docs/open-integration.en.md +5 -67
- package/docs/open-integration.md +5 -67
- package/docs/public-resource-protocol.en.md +8 -44
- package/docs/public-resource-protocol.md +8 -43
- package/docs/security-model.en.md +10 -132
- package/docs/security-model.md +10 -132
- package/docs/server-integration-contract.en.md +12 -813
- package/docs/server-integration-contract.md +12 -825
- package/examples/ecnu.enterprise-profile.example.json +16 -20
- package/examples/enterprise-profile.example.json +16 -20
- package/examples/identity-only.example.json +7 -2
- package/examples/litellm.enterprise-profile.example.json +10 -0
- package/examples/oidc-llm.enterprise-profile.example.json +13 -0
- package/examples/resources-discovery.example.json +7 -9
- package/lib/callback-page.js +5 -5
- package/lib/client.js +31 -48
- package/lib/desktop-oidc.js +7 -11
- package/lib/gateway-backend.js +443 -0
- package/lib/gateway-protocol.js +6 -0
- package/lib/index.js +14 -15
- package/lib/litellm-protocol.js +117 -0
- package/lib/model-resource-transport.js +19 -0
- package/lib/oidc-llm-protocol.js +87 -0
- package/lib/oidc.js +40 -338
- package/lib/profile.js +42 -74
- package/lib/provider/authorization-scope.js +46 -0
- package/lib/provider/core.js +5 -16
- package/lib/provider/index.js +11 -2
- package/lib/transport.js +5 -0
- package/lib/typert-schemas.js +1 -1
- package/package.json +2 -2
- package/protocol/openapi.yaml +33 -240
- package/protocol/resources.openapi.yaml +8 -9
- package/schema/enterprise-profile.v1alpha1.schema.json +508 -107
package/docs/getting-started.md
CHANGED
|
@@ -1,237 +1,28 @@
|
|
|
1
|
-
#
|
|
1
|
+
# 接入指南
|
|
2
2
|
|
|
3
3
|
**简体中文** | [English](getting-started.en.md)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
新客户端的机构模型请求使用登录获得的 Access Token。先选择服务端实际提供的契约,再配置完整发现地址。
|
|
6
6
|
|
|
7
|
-
|
|
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
|
-
|
|
|
20
|
-
|
|
|
21
|
-
|
|
|
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
|
-
|
|
13
|
+
OIDC 模式需要浏览器登录、Code + PKCE、有效 ID Token 和 UserInfo。服务端必须明确授权该 Access Token 调用模型;仅填一个模型 URL 不会赋予权限。详见[服务端契约](server-integration-contract.md)。
|
|
224
14
|
|
|
225
|
-
|
|
15
|
+
## Host 配置
|
|
226
16
|
|
|
227
|
-
|
|
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
|
-
|
|
230
|
-
{ "supportsReasoningEffort": false }
|
|
231
|
-
```
|
|
19
|
+
仅用于包含本分支源码的开发装配,尚未发布。按[开发说明](development.md)构建和验证。正式装配应固定通过审查的已发布包,不能把新配置直接交给尚不支持它的旧版本。
|
|
232
20
|
|
|
233
|
-
|
|
21
|
+
## 登录与使用
|
|
234
22
|
|
|
235
|
-
|
|
23
|
+
1. 用户在浏览器完成授权,客户端校验 state、PKCE 及适用的身份信息。
|
|
24
|
+
2. 登录后自动获取模型目录,使用同一授权连接 DSH Provider,不再要求创建模型 Key。
|
|
25
|
+
3. 临近到期时自动刷新,刷新后保留原身份和授权上下文。
|
|
26
|
+
4. 退出清理本地状态,停止使用旧授权。Token 的服务端寿命按部署策略执行。
|
|
236
27
|
|
|
237
|
-
|
|
28
|
+
配额继续由机构扩展提供,见[账户扩展](account-extensions.md)。旧配置请按[迁移说明](key-binding-protocol.md)改为 Token 接入。配置和日志不得包含密码、client secret 或用户 Token。
|
|
@@ -1,227 +1,17 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Migrating legacy Key Binding
|
|
2
2
|
|
|
3
3
|
[简体中文](key-binding-protocol.md) | **English**
|
|
4
4
|
|
|
5
|
-
|
|
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
|
-
|
|
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
|
-
|
|
9
|
+
## Migration
|
|
10
10
|
|
|
11
|
-
|
|
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
|
-
|
|
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.
|