@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.
- 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 +10 -31
- package/docs/enterprise-profile.md +11 -32
- 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 +14 -19
- package/examples/enterprise-profile.example.json +14 -19
- package/examples/litellm.enterprise-profile.example.json +9 -0
- package/examples/oidc-llm.enterprise-profile.example.json +12 -0
- package/examples/resources-discovery.example.json +5 -8
- 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 +88 -0
- package/lib/oidc.js +37 -323
- package/lib/profile.js +34 -40
- package/lib/provider/authorization-scope.js +46 -0
- package/lib/provider/index.js +11 -2
- 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 +509 -107
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# 网关认证接入
|
|
2
|
+
|
|
3
|
+
**简体中文** | [English](README_EN.md)
|
|
4
|
+
|
|
5
|
+
本分支新增 LiteLLM native OAuth 支持,以及默认关闭的 [oidc-llm 实验适配器](experimental-oidc-llm.md),尚未发布 npm 或桌面版本。仅身份 oidc 配置保留;旧 Key Binding 模型流程已移除,迁移见[说明](../key-binding-protocol.md)。新的 **oidc-llm** 仍是[协议草案](oidc-llm-draft.md),实验实现不代表协议已定稿。
|
|
6
|
+
|
|
7
|
+
## 选择接入方式
|
|
8
|
+
|
|
9
|
+
配置已有 LiteLLM 网关请从 [LiteLLM 接入指南](litellm-setup.md)开始;本页描述底层协议和宿主集成要求。
|
|
10
|
+
|
|
11
|
+
| 服务端 | 配置 | 模型凭据 | 客户端注册 |
|
|
12
|
+
| --- | --- | --- | --- |
|
|
13
|
+
| 纯身份 OIDC | 仅 oidc,不配置 provider | 无机构模型凭据 | 预注册 public client |
|
|
14
|
+
| LiteLLM 1.101.0 native contract 1 | `auth.discoveryUrl` | 登录返回的 Access Token | 每次登录动态注册实际本机回调 |
|
|
15
|
+
| oidc-llm 0.1 实验 | `auth` + 显式实验开关与身份模式 | Access Token | 已实现预注册 public client |
|
|
16
|
+
|
|
17
|
+
LiteLLM 不需要实现 EduWork 的 Key Binding。普通 OIDC 的 Access Token 也不会因为配置了模型 URL 就获得推理权限;须配置明确的 Token 网关契约。配额和团队管理不纳入本次统一协议;LiteLLM 自己的团队选择留在网关网页,客户端仅保存不透明的授权上下文用于防止刷新串号。
|
|
18
|
+
|
|
19
|
+
## LiteLLM 配置
|
|
20
|
+
|
|
21
|
+
在含本功能的构建中,把下列对象放入 `config/eduwork.jsonc` 的 `organizations` 数组;直接使用插件时放入 `profiles`。完整示例见 [Enterprise Profile](../../examples/litellm.enterprise-profile.example.json)。
|
|
22
|
+
|
|
23
|
+
```json
|
|
24
|
+
{
|
|
25
|
+
"schemaVersion": "dsh-oidc/v1alpha1",
|
|
26
|
+
"id": "example-gateway",
|
|
27
|
+
"displayName": "示例模型网关",
|
|
28
|
+
"auth": {
|
|
29
|
+
"discoveryUrl": "https://gateway.example.org/.well-known/litellm-cli-auth",
|
|
30
|
+
"expectedIssuer": "https://gateway.example.org"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
`discoveryUrl` 是完整地址,不由客户端猜路径。`expectedIssuer` 可省略,但部署方建议填写;LiteLLM 适配器始终要求 issuer、resource、认证端点与发现地址同源,且 resource 与 issuer 完整字符串一致。生产使用 HTTPS;实验只允许显式设置 `allowInsecureDevelopment: true` 后的 loopback HTTP。不允许通过 `insecureDevelopmentOrigin` 放宽此新协议到任意明文地址。
|
|
36
|
+
|
|
37
|
+
`auth` 与 `oidc`、`keyBinding` 互斥;LiteLLM 配置不填写固定 `clientId`、secret、scope 或 `provider.baseURL`。模型 API 基址由已校验的 issuer 追加 `/v1`,保留部署路径前缀。可选 `provider` 支持唯一的 `id`、显示名、上下文/输出限制和经管理员核实的 `models` 能力;只能使用 `modelSource: "discovery"`。模型能否出现由当前账户的 `/v1/models` 决定,配置里的模型信息只是能力补充,不会绕过授权。
|
|
38
|
+
|
|
39
|
+
普通 `/models` 只有 ID 时默认视为文本模型、不推测思考或图像能力。可用模型列表为空时保持空列表。读取失败显示目录暂不可用;不会沿用另一个账户的模型列表。
|
|
40
|
+
|
|
41
|
+
插件使用 `backend: "desktop"` 或本机 `backend: "web"`;旧 `native` 桥已移除。示例插件配置:
|
|
42
|
+
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"backend": "desktop",
|
|
46
|
+
"profilePathEnv": "EDUWORK_OIDC_PROFILE"
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
环境变量指向上述 Profile JSON 文件。桌面宿主须按[宿主接入指南](../desktop-host.md)提供 `desktopServices.openExternal` 和 Credential Provider;网页宿主保持既有本机单用户边界。
|
|
51
|
+
|
|
52
|
+
## LiteLLM native contract 1 接口
|
|
53
|
+
|
|
54
|
+
以下描述对应 **LiteLLM v1.101.0**,不是我们要求 LiteLLM 实现的新协议。端点名称来自发现响应,表中的路径为该版本默认部署示例。
|
|
55
|
+
|
|
56
|
+
### 1. 发现
|
|
57
|
+
|
|
58
|
+
无凭据 `GET /.well-known/litellm-cli-auth`,成功 200:
|
|
59
|
+
|
|
60
|
+
```json
|
|
61
|
+
{
|
|
62
|
+
"contract_version": 1,
|
|
63
|
+
"issuer": "https://gateway.example.org",
|
|
64
|
+
"authorization_endpoint": "https://gateway.example.org/authorize",
|
|
65
|
+
"token_endpoint": "https://gateway.example.org/token",
|
|
66
|
+
"registration_endpoint": "https://gateway.example.org/register",
|
|
67
|
+
"revocation_endpoint": "https://gateway.example.org/revoke",
|
|
68
|
+
"resource": "https://gateway.example.org",
|
|
69
|
+
"response_types_supported": ["code"],
|
|
70
|
+
"grant_types_supported": ["authorization_code", "refresh_token"],
|
|
71
|
+
"code_challenge_methods_supported": ["S256"],
|
|
72
|
+
"token_endpoint_auth_methods_supported": ["none"],
|
|
73
|
+
"revocation_endpoint_auth_methods_supported": ["none"]
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
客户端核对所有必需能力和 URL,未知版本、缺失能力、混入 `oidc_llm` 标志均报错。不能仅根据域名、一个 `contract_version` 字段或没有 ID Token 来猜协议。配置/端点绑定变化后,旧 Token 不发送到新服务。
|
|
78
|
+
|
|
79
|
+
### 2. 动态注册
|
|
80
|
+
|
|
81
|
+
先绑定 `127.0.0.1` 临时端口,再向 registration endpoint 发 JSON POST:
|
|
82
|
+
|
|
83
|
+
```json
|
|
84
|
+
{
|
|
85
|
+
"client_name": "EduWork",
|
|
86
|
+
"redirect_uris": ["http://127.0.0.1:53187/oauth/callback"],
|
|
87
|
+
"token_endpoint_auth_method": "none",
|
|
88
|
+
"grant_types": ["authorization_code", "refresh_token"],
|
|
89
|
+
"response_types": ["code"]
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
成功 201,返回 `client_id`、`client_id_issued_at`、`redirect_uris`、`token_endpoint_auth_method`、`grant_types` 和 `response_types`。回调必须与注册请求一致。该版本允许 1–3 个回调,每个至多 256 字符;EduWork 只注册本次实际回调。`client_id` 是网关签发的 opaque 注册标识,不是用户 ID;不能用任意字符串代替。刷新复用原 client ID,不重新注册。
|
|
94
|
+
|
|
95
|
+
### 3. 浏览器授权
|
|
96
|
+
|
|
97
|
+
GET authorization endpoint,参数:
|
|
98
|
+
|
|
99
|
+
| 参数 | 客户端值 |
|
|
100
|
+
| --- | --- |
|
|
101
|
+
| `response_type` | `code` |
|
|
102
|
+
| `client_id` | 注册返回值 |
|
|
103
|
+
| `redirect_uri` | 与注册精确一致 |
|
|
104
|
+
| `state` | 每次随机,回调必须匹配,只消费一次 |
|
|
105
|
+
| `code_challenge` / `code_challenge_method` | PKCE SHA-256 / `S256` |
|
|
106
|
+
| `resource` | 发现响应原值 |
|
|
107
|
+
|
|
108
|
+
必须发送 `resource`,否则该版本可能进入 MCP 授权路径。Native 流程不提供 OIDC 的 nonce/ID Token 校验,也未按应用 scope 实现权限隔离,客户端不发送虚构的 `openid` 或自定义模型 scope。
|
|
109
|
+
|
|
110
|
+
用户在网关登录、选择网关支持的授权上下文并同意后,浏览器返回 `code` 与 `state`;拒绝返回 `error=access_denied` 与 `state`。无效 client/回调可能直接收到 JSON 错误。授权页面及其内部 `/authorize/complete` 由 LiteLLM 管理,不属于 EduWork Host 调用的认证 API。
|
|
111
|
+
|
|
112
|
+
### 4. 换码与刷新
|
|
113
|
+
|
|
114
|
+
向 token endpoint 发 `application/x-www-form-urlencoded` POST:
|
|
115
|
+
|
|
116
|
+
| 操作 | 表单字段 |
|
|
117
|
+
| --- | --- |
|
|
118
|
+
| 换码 | `grant_type=authorization_code`、`client_id`、`code`、`redirect_uri`、`code_verifier`、`resource` |
|
|
119
|
+
| 刷新 | `grant_type=refresh_token`、`client_id`、`refresh_token`、`resource` |
|
|
120
|
+
|
|
121
|
+
成功 200,两种操作均返回:
|
|
122
|
+
|
|
123
|
+
```json
|
|
124
|
+
{
|
|
125
|
+
"access_token": "OPAQUE_ACCESS_TOKEN",
|
|
126
|
+
"token_type": "Bearer",
|
|
127
|
+
"expires_in": 3600,
|
|
128
|
+
"refresh_token": "OPAQUE_REFRESH_TOKEN",
|
|
129
|
+
"user_id": "example-user",
|
|
130
|
+
"team_id": null
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Access Token 是不透明凭据,不能自行解析为 JWT。`user_id` 是非空字符串,`team_id` 是字符串或 null,二者在刷新后必须保持一致;不一致要求重新登录。`expires_in` 以响应为准:上例 1 小时仅为示例,该版本默认 24 小时且可配置。Refresh Token 每次轮换、单次使用,其 14 天期限随新签发重新计算,不是整个登录的绝对寿命。
|
|
135
|
+
|
|
136
|
+
Host 在临近到期时刷新,同一授权的并发请求共用一次刷新,将新 Token 对整体保存后再使用。失败的目录读取、403、429、5xx 不会一概清除登录;明确 `invalid_grant`/`invalid_client` 或刷新身份改变才要求重新登录。重定向不会携带 code/token 自动跟随。已经开始的生成和 SSE 不因认证失败而由本层自动重放。
|
|
137
|
+
|
|
138
|
+
模型请求在准备时绑定当前授权。退出或更换账户/授权上下文后,已准备但尚未发送的请求不能改用新账户凭据;正在接收的请求会取消,迟到的正文与流式内容不再交给调用方。相同授权内的 Token 刷新不会中断生成。这是客户端的本地隔离,不代表网关已立即撤销 Access Token,也不保证上游推理或计费同步停止。
|
|
139
|
+
|
|
140
|
+
### 5. 用户资料与模型
|
|
141
|
+
|
|
142
|
+
| 请求 | 鉴权与处理 |
|
|
143
|
+
| --- | --- |
|
|
144
|
+
| `GET /user/info` | Bearer Access Token;返回 `user_id`、`user_info` 等。只接收匹配主体的 `user_info.user_alias` 作为可选显示名;失败降级为 Token 响应的 user ID |
|
|
145
|
+
| `GET /v1/models` | Bearer Access Token;OpenAI 风格 `data` 数组,每项 `id`。用于当前授权的模型目录 |
|
|
146
|
+
| `POST /v1/chat/completions` | 相同 Bearer;普通 JSON 或 `stream=true` 的 SSE(含 `[DONE]`),复用 DSH 模型适配器 |
|
|
147
|
+
|
|
148
|
+
`/user/info` 是 LiteLLM adapter 的固定映射,native discovery 没有 `userinfo_endpoint`。其完整响应可能包含 Key、团队、预算等管理信息,不能直接传给 UI、日志或诊断包。模型 Token 不写成长期 `EDUWORK_API_KEY` 副本;主会话与子代理在实际请求时共用 Host 的有效凭据解析入口。
|
|
149
|
+
|
|
150
|
+
### 6. 撤销与错误
|
|
151
|
+
|
|
152
|
+
POST revocation endpoint,表单 `token=<refresh_token>&client_id=<registered_client>`。该版本以 200 `{}` 返回撤销结果;有效 client 下未知、过期、重复的 Token 可得到相同成功形状。非法 client 返回 401;协调服务或其他服务器异常可能返回 503/500。
|
|
153
|
+
|
|
154
|
+
**只撤销提交的 Refresh Token,不能宣称立即撤销全部 Access Token 或整个刷新家族。** Access Token 仍按网关有效期处理。客户端退出先清除本地授权及模型目录,再尝试远端撤销;远端失败记录不含凭据的警告,不阻止本地退出。当前客户端没有跨重启的待撤销重试队列。
|
|
155
|
+
|
|
156
|
+
常见 OAuth 错误为 400 的 `invalid_request`、`invalid_grant`、`invalid_target`、`unsupported_grant_type`;参数结构错误也可能是 FastAPI 的 422。403 表示请求无权限;429/5xx 为独立的资源/服务错误,不能解释成必定需要重新登录。用户 Token 的实际权限由该版网关决定,不宣称已限制为“仅模型推理”。
|
|
157
|
+
|
|
158
|
+
## 现有 OIDC 与后续迁移
|
|
159
|
+
|
|
160
|
+
纯身份 OIDC 与 oidc-llm 的 OIDC 模式共用 Discovery issuer、PKCE S256、state、nonce、RS256 ID Token 和 UserInfo sub 一致性校验。Key Binding 与旧凭据引用迁移已移除,模型授权改用网关 Token。相关接口见[服务端契约](../server-integration-contract.md)、[Profile 规范](../enterprise-profile.md)。没有为兼容 LiteLLM 放松这些检查。
|
|
161
|
+
|
|
162
|
+
新 oidc-llm 的 UserInfo 从发现的 `userinfo_endpoint` 获取,复用标准主体和资料字段。实验配置及实际限制见[实验接入](experimental-oidc-llm.md),尚待讨论的 scope、生命周期和撤销保证见[草案](oidc-llm-draft.md)。真实服务完成验收前,不迁移已有机构配置。
|
|
163
|
+
|
|
164
|
+
## 开发验证
|
|
165
|
+
|
|
166
|
+
包内执行 `npm ci`、`npm run check`。合成测试覆盖纯身份 OIDC、安全发现、真实 loopback、刷新竞争、账户切换、目录隔离和错误行为;真实 LiteLLM 联调需单独运行本地网关并完成浏览器登录、普通/SSE、刷新、重启和退出验收。HTTP 同意页驱动、模拟到期或 mock 模型不等价于完整桌面、自然到期或真实推理验收。测试账号和 Token 不进入公开仓库。
|
|
167
|
+
|
|
168
|
+
官方依据:[v1.101.0](https://github.com/BerriAI/litellm/releases/tag/v1.101.0)、[native flow](https://github.com/BerriAI/litellm/blob/v1.101.0/litellm/proxy/_experimental/mcp_server/gateway_dcr_flow.py)、[HTTP routes](https://github.com/BerriAI/litellm/blob/v1.101.0/litellm/proxy/_experimental/mcp_server/discoverable_endpoints.py)、[proxy credentials](https://github.com/BerriAI/litellm/blob/v1.101.0/litellm/proxy/_experimental/mcp_server/proxy_api_credentials.py)。
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Gateway authentication
|
|
2
|
+
|
|
3
|
+
[简体中文](README.md) | **English**
|
|
4
|
+
|
|
5
|
+
This branch adds LiteLLM native OAuth and an [experimental oidc-llm adapter](experimental-oidc-llm.en.md), disabled by default. Neither is included in a published npm package or desktop Release yet. Identity-only oidc profiles remain supported. Key Binding model flows are removed; see [migration](../key-binding-protocol.en.md). **oidc-llm** remains a [draft](oidc-llm-draft.en.md); the experiment does not finalize the protocol.
|
|
6
|
+
|
|
7
|
+
## Choose a connection
|
|
8
|
+
|
|
9
|
+
Start with the [LiteLLM setup guide](litellm-setup.en.md) to configure an existing gateway. This page describes the underlying protocol and Host integration requirements.
|
|
10
|
+
|
|
11
|
+
| Server | Configuration | Model credential | Client registration |
|
|
12
|
+
| --- | --- | --- | --- |
|
|
13
|
+
| Identity-only OIDC | oidc without provider | No organization model credential | Pre-registered public client |
|
|
14
|
+
| LiteLLM 1.101.0 native contract 1 | `auth.discoveryUrl` | Login Access Token | Dynamically register the actual callback on each login |
|
|
15
|
+
| Experimental oidc-llm 0.1 | `auth` with explicit opt-in and identity mode | Access Token | Static public client implemented |
|
|
16
|
+
|
|
17
|
+
Quota standardization and team management are outside this integration. LiteLLM handles its own team choice in the gateway page; the adapter retains its opaque authorization context solely to detect an unexpected identity change during refresh. An ordinary OIDC Access Token does not automatically authorize model inference.
|
|
18
|
+
|
|
19
|
+
## Configuration
|
|
20
|
+
|
|
21
|
+
In a build containing this feature, add this object to `organizations` in `config/eduwork.jsonc`, or `profiles` when using the plugin directly:
|
|
22
|
+
|
|
23
|
+
```json
|
|
24
|
+
{
|
|
25
|
+
"schemaVersion": "dsh-oidc/v1alpha1",
|
|
26
|
+
"id": "example-gateway",
|
|
27
|
+
"displayName": "Example model gateway",
|
|
28
|
+
"auth": {
|
|
29
|
+
"discoveryUrl": "https://gateway.example.org/.well-known/litellm-cli-auth",
|
|
30
|
+
"expectedIssuer": "https://gateway.example.org"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
See the [complete Profile example](../../examples/litellm.enterprise-profile.example.json). `discoveryUrl` is the complete configured URL. `expectedIssuer` is optional but recommended. Native discovery requires issuer, resource and auth endpoints on the discovery origin; resource must exactly equal issuer. Production uses HTTPS. Explicit `allowInsecureDevelopment: true` permits loopback HTTP only; `insecureDevelopmentOrigin` does not relax this new protocol to arbitrary HTTP hosts.
|
|
36
|
+
|
|
37
|
+
`auth` is mutually exclusive with `oidc` and `keyBinding`. Do not supply a static `clientId`, secret, scopes or `provider.baseURL`. The adapter appends `/v1` to the validated issuer, preserving any deployment prefix. An optional `provider` may supply a distinct `id`, display name, context/output limits and reviewed per-model capabilities in `models`; only `modelSource: "discovery"` is supported. The current account's model list determines visibility. Local model metadata cannot grant access to an absent model.
|
|
38
|
+
|
|
39
|
+
Models with only an ID default to text-only without assumed reasoning support. An empty catalog stays empty; a failed fetch never adopts another account's catalog.
|
|
40
|
+
|
|
41
|
+
Use `backend: "desktop"` or local `backend: "web"`; the legacy `native` account bridge has been removed. A direct plugin configuration can use `{"backend":"desktop","profilePathEnv":"EDUWORK_OIDC_PROFILE"}` with the environment variable pointing to a Profile JSON file. The desktop Host supplies `desktopServices.openExternal` and a Credential Provider as described in the [Host guide](../desktop-host.md). Web keeps the existing single-user loopback boundary.
|
|
42
|
+
|
|
43
|
+
## LiteLLM native contract 1
|
|
44
|
+
|
|
45
|
+
The wire behavior below is pinned to **LiteLLM v1.101.0**. Endpoints come from discovery; paths are the default deployment examples, not a new specification imposed on LiteLLM.
|
|
46
|
+
|
|
47
|
+
1. **Discovery:** unauthenticated GET `/.well-known/litellm-cli-auth`, 200 JSON containing integer `contract_version: 1`, `issuer`, `resource`, `authorization_endpoint`, `token_endpoint`, `registration_endpoint`, `revocation_endpoint`; required capabilities are `response_types_supported: ["code"]`, `grant_types_supported` containing code and refresh, `code_challenge_methods_supported` containing `S256`, and token/revocation auth methods containing `none`. Unknown versions, missing capabilities and an `oidc_llm` marker fail explicitly. Detection never depends on a brand in the URL or a missing ID Token. A changed configuration/endpoint binding cannot receive saved tokens.
|
|
48
|
+
2. **Registration:** bind an actual `http://127.0.0.1:<port>/oauth/callback`, then POST JSON to the registration endpoint with `client_name: "EduWork"`, `redirect_uris: [actualCallback]`, `token_endpoint_auth_method: "none"`, code/refresh grant types and `response_types: ["code"]`. The 201 response contains `client_id`, `client_id_issued_at`, registered redirects, auth method, grants and response types. The callback must match. This server allows 1–3 redirects of at most 256 characters; EduWork registers one. The opaque client ID is not a user ID; each login registers, while refresh reuses its original ID.
|
|
49
|
+
3. **Authorize:** navigate the system browser to the advertised endpoint with `response_type=code`, registered `client_id`, exact `redirect_uri`, random one-use `state`, S256 PKCE challenge and exact discovered `resource`. Omitting resource can enter the MCP flow. Native auth does not supply OIDC ID Tokens or enforce application scopes; the client invents neither nonce/`openid` requirements nor model scopes. Gateway login/consent returns code + state, or `access_denied` + state. The gateway's internal `/authorize/complete` form is not a Host API.
|
|
50
|
+
4. **Exchange/refresh:** POST form data to token endpoint. Exchange sends `grant_type=authorization_code`, client ID, code, redirect URI, verifier and resource. Refresh sends `grant_type=refresh_token`, client ID, refresh token and resource. Both return 200 with nonempty `access_token`, `refresh_token`, `token_type: "Bearer"`, positive integer `expires_in`, nonempty `user_id`, and `team_id` (string or null). Access tokens are opaque. The response lifetime is authoritative; default access lifetime in this version is 24 hours and configurable. Rotating refresh tokens are single-use, with a new 14-day expiry on each issuance. Subject and opaque team must remain unchanged during refresh.
|
|
51
|
+
5. **Identity/models:** GET `/user/info`, GET `/v1/models`, POST `/v1/chat/completions` all use the Access Token as Bearer. `/user/info` is a native adapter mapping, not an advertised OIDC `userinfo_endpoint`; only matching `user_id` and optional `user_info.user_alias` are projected. Failure falls back to the token subject. Its keys, teams and budgets are never returned wholesale to the renderer. Models use OpenAI-style `data[].id`. Inference reuses the DSH adapter for JSON and SSE with `[DONE]`. No permanent `EDUWORK_API_KEY` copy is created; main and subagents resolve fresh credentials through the shared Host.
|
|
52
|
+
6. **Revoke:** POST form `token=<refresh>&client_id=<registeredClient>` to the advertised revoke endpoint. 200 `{}` also covers unknown/expired/repeated tokens under a valid client. Invalid client can return 401; coordination/server failures can return 503/500. **Only the submitted refresh token is revoked, not a whole family or all access tokens.** Access tokens retain the server's expiry behavior. Local logout clears tokens and routes before attempting remote revocation; a failure emits a credential-free warning. This client does not yet persist a revocation retry queue across restarts.
|
|
53
|
+
|
|
54
|
+
See the [Chinese wire reference](README.md#litellm-native-contract-1-接口) for complete JSON examples. Common token errors include 400 `invalid_request`, `invalid_grant`, `invalid_target`, `unsupported_grant_type`; malformed input can instead use FastAPI 422. 403 permissions, 429 limits and 5xx outages do not generally erase login. Do not claim native tokens have server-enforced inference-only scopes.
|
|
55
|
+
|
|
56
|
+
The Host merges concurrent refreshes for one authorization and persists the complete rotated pair before use. A still-valid token can survive a temporary refresh outage; an expired token stops. Terminal grant errors or changed refresh identity require sign-in. Credential-bearing requests do not follow redirects. This authentication layer never automatically replays generation or a partially consumed SSE; safe reads may refresh and retry once after 401.
|
|
57
|
+
|
|
58
|
+
Model calls bind to the current authorization when prepared. After logout or account/authorization replacement, a prepared call cannot acquire the new account's credential, active requests are cancelled, and late response bytes or stream content are discarded. Refresh within the same authorization keeps generation running. This is local client isolation, not immediate server-side Access Token revocation or a guarantee that upstream inference and billing stop at the same time.
|
|
59
|
+
|
|
60
|
+
## Existing OIDC and the future draft
|
|
61
|
+
|
|
62
|
+
Identity-only OIDC and the oidc-llm OIDC mode share issuer, PKCE, state, nonce, RS256 ID Token and matching UserInfo subject validation. Key Binding and legacy credential-name migration have been removed; model authorization uses gateway Tokens. See the [existing server contract](../server-integration-contract.md) and [Profile reference](../enterprise-profile.md). These checks were not weakened for LiteLLM.
|
|
63
|
+
|
|
64
|
+
The oidc-llm adapter discovers `userinfo_endpoint` and reuses standard subject and identity claims. See [experimental integration](experimental-oidc-llm.en.md) for configuration and actual limits. Scope, lifetimes and revocation guarantees remain under review in the [draft](oidc-llm-draft.en.md). Do not migrate an existing institution configuration before real-server acceptance.
|
|
65
|
+
|
|
66
|
+
## Validation
|
|
67
|
+
|
|
68
|
+
Run `npm ci` and `npm run check` in the package. Synthetic tests cover identity-only OIDC, discovery validation, real loopback callbacks, refresh races, account/catalog isolation and errors. Live gateway acceptance separately covers browser authorization, ordinary/SSE inference, refresh, restart and logout. An HTTP form driver, simulated near-expiry and a mock inference backend do not prove desktop UI, natural expiry or real inference. Keep test credentials outside the public repository.
|
|
69
|
+
|
|
70
|
+
Official baseline: [release](https://github.com/BerriAI/litellm/releases/tag/v1.101.0), [native flow](https://github.com/BerriAI/litellm/blob/v1.101.0/litellm/proxy/_experimental/mcp_server/gateway_dcr_flow.py), [HTTP routes](https://github.com/BerriAI/litellm/blob/v1.101.0/litellm/proxy/_experimental/mcp_server/discoverable_endpoints.py), [proxy credentials](https://github.com/BerriAI/litellm/blob/v1.101.0/litellm/proxy/_experimental/mcp_server/proxy_api_credentials.py).
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Experimental oidc-llm integration
|
|
2
|
+
|
|
3
|
+
[简体中文](experimental-oidc-llm.md) | **English**
|
|
4
|
+
|
|
5
|
+
This branch provides an opt-in oidc-llm 0.1 adapter, disabled by default and not released. The protocol remains under review. This page describes implemented client behavior; it does not claim that the [complete draft](oidc-llm-draft.en.md) is finalized or that a server has passed acceptance.
|
|
6
|
+
|
|
7
|
+
## Configuration
|
|
8
|
+
|
|
9
|
+
Add this object to desktop `organizations` or plugin `profiles`. The server must publish the complete `oidc_llm` extension; ordinary OIDC metadata cannot implicitly enable model access.
|
|
10
|
+
|
|
11
|
+
```json
|
|
12
|
+
{
|
|
13
|
+
"schemaVersion": "dsh-oidc/v1alpha1",
|
|
14
|
+
"id": "example-models",
|
|
15
|
+
"displayName": "Example model service",
|
|
16
|
+
"auth": {
|
|
17
|
+
"discoveryUrl": "https://models.example.org/.well-known/openid-configuration",
|
|
18
|
+
"expectedIssuer": "https://models.example.org",
|
|
19
|
+
"experimentalOidcLlm": true,
|
|
20
|
+
"clientId": "replace-with-public-client-id",
|
|
21
|
+
"identityMode": "oidc"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Select `identityMode` explicitly. Neither mode falls back to the other:
|
|
27
|
+
|
|
28
|
+
| Mode | Requested scopes | Identity validation |
|
|
29
|
+
| --- | --- | --- |
|
|
30
|
+
| `oidc` | `openid profile offline_access llm:models:read llm:invoke`, with consent | Initial RS256 ID Token required; signature, issuer, aud/azp, nonce, time, optional at_hash and UserInfo subject are verified |
|
|
31
|
+
| `oauth` | `llm:profile llm:models:read llm:invoke` | Reads sub from the discovered UserInfo-shaped endpoint; does not claim OIDC authentication |
|
|
32
|
+
|
|
33
|
+
Only static public-client registration is implemented; no client secret is accepted. Register the actual IPv4 loopback callback `http://127.0.0.1:<random-port>/oauth/callback`. Dynamic registration remains future work.
|
|
34
|
+
|
|
35
|
+
When discovery declares `authorization_response_iss_parameter_supported: true`, both successful and error authorization responses must include `iss` exactly matching the discovered `issuer`. A missing value produces `gateway_callback_issuer_missing`; repeated, empty or mismatched values produce `gateway_callback_issuer_invalid`. The client does not exchange the code. Ask the authentication service administrator to align discovery and callback behavior before starting a new sign-in. The desktop callback listener closes when the flow ends; refreshing an old callback URL cannot resume sign-in.
|
|
36
|
+
|
|
37
|
+
Production endpoints require HTTPS. An isolated experiment may reuse `allowInsecureDevelopment: true` and `insecureDevelopmentOrigin`, with a mandatory `expectedIssuer` pin. HTTP is restricted to loopback or that exact origin, never an entire private network. LiteLLM native retains its loopback-only exception.
|
|
38
|
+
|
|
39
|
+
## Shared implementation and limits
|
|
40
|
+
|
|
41
|
+
Both gateway adapters reuse discovery transport, Code+PKCE, browser/callbacks, the Host credential vault, single-flight refresh, model catalogs, the DSH Provider and streaming authorization isolation. The OIDC identity mode directly reuses the existing strict verifier. Standalone identity-only `oidc` remains supported. Legacy model Key Binding has been removed; see the [migration guide](../key-binding-protocol.en.md).
|
|
42
|
+
|
|
43
|
+
Access tokens stay opaque. Discovered `api_base` and UserInfo must share the resource origin; authentication endpoints only receive their designated credentials, without redirects. Changed configuration/discovery bindings cannot reuse old authorization. Token responses require actual scope, positive integer expiry and a refresh token; grants cannot expand or omit required connection permissions. The server's expiry is honored without enforcing the unagreed 15-minute proposal.
|
|
44
|
+
|
|
45
|
+
Refresh may omit an ID Token. If present, its original issuer, subject, audience, optional auth_time and nonce are checked. Failed validation after rotation revokes the new credentials and requires sign-in instead of continuing with a possibly consumed old refresh token. Temporary Token endpoint failures preserve still-valid authorization.
|
|
46
|
+
|
|
47
|
+
Catalogs retain shared conservative capability mapping: ID-only rows support text without inferred vision or reasoning. Optional draft model capability fields are not consumed yet; use reviewed provider configuration when needed.
|
|
48
|
+
|
|
49
|
+
Institution extensions can use the existing Host-only `modelResourceFetch(profileID, relativePath)`. Legacy connections use their managed model Key; experimental connections use the current authorized Access Token. Both reuse path restrictions, GET, bounded bodies and logout isolation. The public plugin makes no implicit quota request and adds no quota RPC/fields. Extensions must be installed explicitly; the server must define and enforce their authorization.
|
|
50
|
+
|
|
51
|
+
Logout stops local requests before submitting refresh-token revocation; 200 empty and JSON responses are accepted. Remote failure only produces a sanitized warning. A persistent revocation retry queue is not implemented, so that draft proposal is not claimed. Refresh-family revocation, remaining Access Token validity, scope enforcement and model filtering still require real-server acceptance.
|
|
52
|
+
|
|
53
|
+
References: [OIDC refresh response](https://openid.net/specs/openid-connect-core-1_0.html#RefreshTokenResponse), [authorization response issuer](https://www.rfc-editor.org/rfc/rfc9207.html).
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# oidc-llm 实验接入
|
|
2
|
+
|
|
3
|
+
**简体中文** | [English](experimental-oidc-llm.en.md)
|
|
4
|
+
|
|
5
|
+
本分支提供 oidc-llm 0.1 的实验适配器,默认关闭,尚未发布。协议仍在讨论;本页描述已实现的客户端边界,不表示[完整草案](oidc-llm-draft.md)已经定稿或服务端已经通过验收。
|
|
6
|
+
|
|
7
|
+
## 配置
|
|
8
|
+
|
|
9
|
+
在桌面配置的 `organizations` 数组或插件的 `profiles` 中填写以下对象。服务器须明确发布完整的 `oidc_llm` 扩展;普通 OIDC 文档不会自动启用模型访问。
|
|
10
|
+
|
|
11
|
+
```json
|
|
12
|
+
{
|
|
13
|
+
"schemaVersion": "dsh-oidc/v1alpha1",
|
|
14
|
+
"id": "example-models",
|
|
15
|
+
"displayName": "示例模型服务",
|
|
16
|
+
"auth": {
|
|
17
|
+
"discoveryUrl": "https://models.example.org/.well-known/openid-configuration",
|
|
18
|
+
"expectedIssuer": "https://models.example.org",
|
|
19
|
+
"experimentalOidcLlm": true,
|
|
20
|
+
"clientId": "replace-with-public-client-id",
|
|
21
|
+
"identityMode": "oidc"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
必须显式选择 `identityMode`。两种模式不自动互相降级:
|
|
27
|
+
|
|
28
|
+
| 模式 | 请求范围 | 身份验证 |
|
|
29
|
+
| --- | --- | --- |
|
|
30
|
+
| `oidc` | `openid profile offline_access llm:models:read llm:invoke`,并请求 consent | 首次必须有 RS256 ID Token;验证签名、issuer、aud/azp、nonce、时间、可选 at_hash 与 UserInfo sub |
|
|
31
|
+
| `oauth` | `llm:profile llm:models:read llm:invoke` | 从发现的 UserInfo 格式接口读取 sub;不宣称完成 OIDC 身份验证 |
|
|
32
|
+
|
|
33
|
+
目前仅实现预注册 public client,不能填写 client secret。服务器注册须允许实际 IPv4 loopback 回调 `http://127.0.0.1:<随机端口>/oauth/callback`。动态注册留待后续实现。
|
|
34
|
+
|
|
35
|
+
发现声明 `authorization_response_iss_parameter_supported: true` 时,成功和错误授权回调都必须带 `iss`,且与发现中的 `issuer` 完全一致。缺失会报告 `gateway_callback_issuer_missing`;重复、空值或不匹配会报告 `gateway_callback_issuer_invalid`。客户端不会继续换取 Token,应由认证服务管理员核对发现声明与回调实现后重新发起登录。桌面回调监听在流程结束后关闭,刷新旧回调地址不能恢复登录。
|
|
36
|
+
|
|
37
|
+
生产端点须为 HTTPS。独立实验环境可复用既有 `allowInsecureDevelopment: true` 和 `insecureDevelopmentOrigin`,但必须同时固定 `expectedIssuer`;HTTP 端点只允许 loopback 或该完整原点,不扩大到整个内网。此例外不改变 LiteLLM native 的 loopback 限制。
|
|
38
|
+
|
|
39
|
+
## 共享实现与边界
|
|
40
|
+
|
|
41
|
+
两套网关适配器共用发现请求、Code+PKCE、浏览器/回调、Host 凭据库、并发刷新合并、模型目录、DSH Provider 与流式请求隔离。OIDC 身份分支直接复用现有严格验证器;保留独立的纯身份 `oidc` 登录;旧模型 Key Binding 已移除,见[迁移说明](../key-binding-protocol.md)。
|
|
42
|
+
|
|
43
|
+
Access Token 按不透明 Bearer 处理。发现中的 `api_base` 与 UserInfo 必须和 resource 同源;认证端点只接收其角色对应的凭据,禁自动重定向。配置或发现绑定改变时不复用旧授权。Token 响应必须提供实际 scope、正整数有效期和 refresh token;scope 不得扩大或缺少本连接需要的权限。有效期按服务器响应执行,不把尚未议定的 15 分钟建议写成硬性上限。
|
|
44
|
+
|
|
45
|
+
刷新可以省略 ID Token;返回时检查原 issuer、sub、aud、可选 auth_time 和 nonce。轮换后的 Token 若验证失败,客户端撤销新凭据并要求重登,避免继续使用可能已消费的旧 refresh token。临时 Token endpoint 故障不会删除仍有效的旧授权。
|
|
46
|
+
|
|
47
|
+
模型目录仍使用共享的保守能力映射:仅有 ID 时启用文本,不从名称猜图像或思考能力。草案中的可选模型能力扩展尚未消费,需要时使用显式审核的 provider 配置。
|
|
48
|
+
|
|
49
|
+
机构扩展可以调用既有 Host-only `modelResourceFetch(profileID, relativePath)`。模型连接统一使用当前获准的 Access Token,共享路径限制、GET、正文大小限制与退出隔离。公共插件不自动查询配额,也不新增配额 RPC 或字段。扩展须显式安装,服务端须自行声明并执行其授权范围。
|
|
50
|
+
|
|
51
|
+
退出立即停止本机请求,再提交 refresh token 撤销;支持 200 空响应或 JSON。远端失败仅记录脱敏警告,当前没有持久化撤销重试队列,不能宣称满足草案中这项提议。服务器的 refresh 家族撤销、Access Token 剩余有效期、scope 隔离和模型过滤仍需真实验收。
|
|
52
|
+
|
|
53
|
+
参考:[OIDC 刷新响应](https://openid.net/specs/openid-connect-core-1_0.html#RefreshTokenResponse)、[授权响应 issuer](https://www.rfc-editor.org/rfc/rfc9207.html)。
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# LiteLLM setup guide
|
|
2
|
+
|
|
3
|
+
[简体中文](litellm-setup.md) | **English**
|
|
4
|
+
|
|
5
|
+
Let users sign in to a LiteLLM gateway from EduWork, discover authorized models, and chat without manually distributing model API keys.
|
|
6
|
+
|
|
7
|
+
[LiteLLM](https://github.com/BerriAI/litellm) provides the gateway; EduWork uses its native OAuth flow. This guide is for administrators of an existing LiteLLM deployment and EduWork desktop users. The protocol baseline is **LiteLLM v1.101.0 / native contract 1**; validate other versions using the checks below. EduWork requires a build containing this feature, which has not yet been published as an npm package or desktop release.
|
|
8
|
+
|
|
9
|
+
## 1. Prepare the server
|
|
10
|
+
|
|
11
|
+
Follow the [official LiteLLM deployment guide](https://docs.litellm.ai/docs/proxy/quick_start) to prepare a gateway, database, and at least one working real model upstream. Configure a test user's account, teams, and model permissions, and verify browser sign-in. Enterprise SSO deployment and licensing requirements are governed by LiteLLM; this guide does not require a new identity provider.
|
|
12
|
+
|
|
13
|
+
Set these environment variables on the existing LiteLLM Proxy process or container, replacing the example with the public HTTPS address users reach, then restart it:
|
|
14
|
+
|
|
15
|
+
```dotenv
|
|
16
|
+
PROXY_BASE_URL=https://gateway.example.org
|
|
17
|
+
EXPERIMENTAL_UI_LOGIN=True
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
`PROXY_BASE_URL` sets the public issuer and endpoints; do not advertise an internal reverse-proxy address. `EXPERIMENTAL_UI_LOGIN` enables the required login feature. See [LiteLLM CLI Authentication](https://docs.litellm.ai/docs/proxy/cli_sso).
|
|
21
|
+
|
|
22
|
+
Forward discovery, authorization, registration, token, revocation, and model routes through the proxy. Preserve query parameters and form bodies, allow streaming SSE, and avoid redirects of authentication POSTs to another origin. Multiple workers or replicas need shared Redis, for example through `general_settings.coordination_redis`, so refresh rotation and revocation are not limited to one process. See the [configuration reference](https://docs.litellm.ai/docs/proxy/config_settings) and [native authentication implementation](https://github.com/BerriAI/litellm/blob/v1.101.0/litellm/proxy/_experimental/mcp_server/discoverable_endpoints.py).
|
|
23
|
+
|
|
24
|
+
From the user's network, check public discovery without credentials:
|
|
25
|
+
|
|
26
|
+
```sh
|
|
27
|
+
curl --fail --silent --show-error https://gateway.example.org/.well-known/litellm-cli-auth
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
The JSON response must satisfy:
|
|
31
|
+
|
|
32
|
+
- `contract_version` is `1`; `issuer` and `resource` are the configured public gateway address.
|
|
33
|
+
- It includes `authorization_endpoint`, `token_endpoint`, `registration_endpoint`, and `revocation_endpoint`.
|
|
34
|
+
- It advertises authorization codes, refresh, PKCE `S256`, and public-client authentication with `none`.
|
|
35
|
+
|
|
36
|
+
See the [protocol reference](README_EN.md) for the full response and constraints. EduWork rejects missing capabilities or inconsistent endpoint bindings; a reachable login page alone does not establish compatibility.
|
|
37
|
+
|
|
38
|
+
## 2. Configure EduWork
|
|
39
|
+
|
|
40
|
+
Select **Open configuration file** in Settings and add this organization to `config/eduwork.jsonc`. Merge into an existing `organizations` array rather than replacing other settings.
|
|
41
|
+
|
|
42
|
+
```json
|
|
43
|
+
{
|
|
44
|
+
"schemaVersion": 1,
|
|
45
|
+
"organizations": [
|
|
46
|
+
{
|
|
47
|
+
"schemaVersion": "dsh-oidc/v1alpha1",
|
|
48
|
+
"id": "example-gateway",
|
|
49
|
+
"displayName": "Example model gateway",
|
|
50
|
+
"auth": {
|
|
51
|
+
"discoveryUrl": "https://gateway.example.org/.well-known/litellm-cli-auth",
|
|
52
|
+
"expectedIssuer": "https://gateway.example.org"
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
]
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
| Field | Value |
|
|
60
|
+
| --- | --- |
|
|
61
|
+
| `id` | A stable organization identifier, unique on this client. |
|
|
62
|
+
| `displayName` | The organization name shown in the account menu. |
|
|
63
|
+
| `auth.discoveryUrl` | The complete discovery document URL supplied by the administrator. |
|
|
64
|
+
| `auth.expectedIssuer` | The expected issuer; recommended, and must match discovery. |
|
|
65
|
+
|
|
66
|
+
Save, exit completely through the tray, and restart EduWork. Closing its window usually leaves the process running.
|
|
67
|
+
|
|
68
|
+
The model API base is the validated issuer with `/v1` appended, preserving any deployment prefix. Do not set `provider.baseURL`. LiteLLM dynamically registers a Client ID for this login: do not configure a static `clientId`, `client_secret`, or scope, or combine this profile with `oidc` or `keyBinding`.
|
|
69
|
+
|
|
70
|
+
Production uses HTTPS. Explicit `allowInsecureDevelopment: true` on the organization entry, alongside `auth`, permits loopback HTTP for local development only, not arbitrary remote HTTP addresses. Keep passwords, Tokens, and upstream keys out of the client configuration.
|
|
71
|
+
|
|
72
|
+
Developers integrating another client can use the [single Profile example](../../examples/litellm.enterprise-profile.example.json) and [desktop Host guide](../desktop-host.en.md) to reuse the same authorization and model modules. Desktop users do not need to assemble a Host themselves.
|
|
73
|
+
|
|
74
|
+
## 3. Sign in and use models
|
|
75
|
+
|
|
76
|
+
1. Select the configured organization in EduWork's account menu and start sign-in. Keep the client running.
|
|
77
|
+
2. Complete sign-in in the system browser. If the gateway asks for a team, select one with the required model permissions and approve access.
|
|
78
|
+
3. The browser returns to a local callback page. Once it confirms completion, return to EduWork.
|
|
79
|
+
4. Select an organization model and send a short message to verify a real upstream response.
|
|
80
|
+
|
|
81
|
+
The `127.0.0.1` callback is a temporary EduWork listener on the user's computer, not the LiteLLM server. Complete sign-in in a browser on the same computer as the client. Do not bookmark or reuse an old authorization link.
|
|
82
|
+
|
|
83
|
+
The client discovers the current authorization's `/v1/models`, sends requests with the Access Token, and refreshes near expiry. Protected local storage restores authorization after restart. Logout clears the local session and attempts Refresh Token revocation; the server controls the remaining lifetime of issued Access Tokens.
|
|
84
|
+
|
|
85
|
+
LiteLLM user and team settings continue to govern model authorization and billing; client configuration cannot grant permissions. This integration does not provide a unified quota panel. Model capabilities come from the catalog and administrator-reviewed configuration. ID-only catalogs default to text models without inferring image or reasoning support from names. See [Profile configuration](../enterprise-profile.en.md) for capability supplements.
|
|
86
|
+
|
|
87
|
+
## 4. Validate before rollout
|
|
88
|
+
|
|
89
|
+
Use a regular account for these checks. An administrator account, model listing, or mock response cannot substitute for actual inference:
|
|
90
|
+
|
|
91
|
+
| Check | Expected result |
|
|
92
|
+
| --- | --- |
|
|
93
|
+
| Sign-in, denied consent, and new sign-in | Success or denial is explicit; an old callback cannot finish a new login. |
|
|
94
|
+
| Catalog and real conversation | Only authorized models appear and a real upstream returns content. |
|
|
95
|
+
| Streaming | Actual conversation content arrives incrementally and ends normally; the proxy does not buffer the entire SSE. |
|
|
96
|
+
| Refresh during use and restart | Requests work after token refresh and sign-in survives restart, without copying Tokens. |
|
|
97
|
+
| User / team isolation | A restricted user cannot list or invoke unauthorized models. |
|
|
98
|
+
| Logout | New organization model requests are unavailable locally and the revoked Refresh Token cannot restore authorization. |
|
|
99
|
+
|
|
100
|
+
A test deployment can shorten token lifetime to exercise refresh. If test tooling simulates near-expiry, record that method. Successful sign-in alone does not validate refresh; a real gateway with a mock upstream does not validate real model inference.
|
|
101
|
+
|
|
102
|
+
## 5. Troubleshooting
|
|
103
|
+
|
|
104
|
+
| Symptom | What to check |
|
|
105
|
+
| --- | --- |
|
|
106
|
+
| Discovery returns 404 or HTML | Check the LiteLLM version, public route, and reverse proxy; expect native contract 1 JSON. |
|
|
107
|
+
| Issuer / endpoint validation fails | Check `PROXY_BASE_URL`, public HTTPS addresses, and `expectedIssuer`; correct deployment settings and sign in again. |
|
|
108
|
+
| Browser reports connection refused at `127.0.0.1` | Keep EduWork running, use a browser on the same computer, and start a new sign-in from its account menu. |
|
|
109
|
+
| Sign-in works but the catalog is empty or inference returns 403 | Check the user, selected team, and model permissions; sign-in does not authorize every model. |
|
|
110
|
+
| Exchange / refresh fails or a request returns 401 | Check token expiry, gateway account status, and server logs; replicas need shared Redis for rotation and revocation. |
|
|
111
|
+
| A reasoning level or input type is unsupported | Follow the current catalog's capabilities; do not force unsupported `reasoningEffort` values or attachments. |
|
|
112
|
+
| Streamed content arrives all at once | Check reverse-proxy SSE buffering and connection timeouts. |
|
|
113
|
+
|
|
114
|
+
When reporting problems, include versions, the failing stage, HTTP status, and redacted errors. Exclude authorization codes, Tokens, and full callback URLs. See the [gateway protocol reference](README_EN.md) for detailed wire fields.
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# LiteLLM 接入指南
|
|
2
|
+
|
|
3
|
+
**简体中文** | [English](litellm-setup.en.md)
|
|
4
|
+
|
|
5
|
+
让用户在 EduWork 中登录 LiteLLM 网关,自动发现获授权的模型并直接对话,无需手动分发模型 API Key。
|
|
6
|
+
|
|
7
|
+
[LiteLLM 项目](https://github.com/BerriAI/litellm)提供网关;EduWork 使用其 native OAuth 流程。本文适用于已有 LiteLLM 部署的管理员和使用 EduWork 桌面的用户。协议基线为 **LiteLLM v1.101.0 / native contract 1**,其他版本需按本文验收。EduWork 端需使用包含本功能的构建;本分支尚未发布 npm 包或桌面版本。
|
|
8
|
+
|
|
9
|
+
## 1. 管理员准备服务端
|
|
10
|
+
|
|
11
|
+
先按 [LiteLLM 官方部署说明](https://docs.litellm.ai/docs/proxy/quick_start)准备网关、数据库和至少一个可用的真实模型上游。为测试用户配置账号、团队与模型权限,并确认该账号能登录网关网页。企业 SSO 的部署和授权要求以 LiteLLM 为准;本指南不要求新增身份提供商。
|
|
12
|
+
|
|
13
|
+
在已有 LiteLLM Proxy 进程或容器中设置以下环境变量,然后重启服务。将示例域名换成用户实际访问的 HTTPS 地址:
|
|
14
|
+
|
|
15
|
+
```dotenv
|
|
16
|
+
PROXY_BASE_URL=https://gateway.example.org
|
|
17
|
+
EXPERIMENTAL_UI_LOGIN=True
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
`PROXY_BASE_URL` 决定公开发现地址中的 issuer 与端点;反向代理后的内网地址不能冒充公开地址。`EXPERIMENTAL_UI_LOGIN` 启用该版本要求的登录功能。配置依据见 [LiteLLM CLI Authentication](https://docs.litellm.ai/docs/proxy/cli_sso)。
|
|
21
|
+
|
|
22
|
+
代理需转发发现、授权、注册、换码、撤销和模型路由,保留查询参数与表单请求体,并允许模型 SSE 持续输出。不要将认证 POST 重定向到另一域名。多 worker / 副本需共享 Redis;可按官方说明配置 `general_settings.coordination_redis`,避免刷新轮换或撤销只在某个进程生效。参见 [LiteLLM 配置参考](https://docs.litellm.ai/docs/proxy/config_settings)和[原生认证实现](https://github.com/BerriAI/litellm/blob/v1.101.0/litellm/proxy/_experimental/mcp_server/discoverable_endpoints.py)。
|
|
23
|
+
|
|
24
|
+
从用户所在网络检查公开发现入口,无需登录或附带 Token:
|
|
25
|
+
|
|
26
|
+
```sh
|
|
27
|
+
curl --fail --silent --show-error https://gateway.example.org/.well-known/litellm-cli-auth
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
应返回 JSON,满足:
|
|
31
|
+
|
|
32
|
+
- `contract_version` 为 `1`,`issuer` 和 `resource` 都是管理员配置的公开网关地址。
|
|
33
|
+
- 包含 `authorization_endpoint`、`token_endpoint`、`registration_endpoint` 和 `revocation_endpoint`。
|
|
34
|
+
- 声明授权码、刷新、PKCE `S256` 和 public client 的 `none` 认证能力。
|
|
35
|
+
|
|
36
|
+
完整发现响应及字段约束见[协议参考](README.md)。EduWork 会检查发现文档,拒绝缺失能力或端点绑定不一致的服务;仅能访问登录页不代表接入完成。
|
|
37
|
+
|
|
38
|
+
## 2. 配置 EduWork
|
|
39
|
+
|
|
40
|
+
在设置中选择 **打开配置文件**,将下面的机构条目加入 `config/eduwork.jsonc`。已有配置时合并 `organizations` 数组,不要覆盖其他配置。
|
|
41
|
+
|
|
42
|
+
```json
|
|
43
|
+
{
|
|
44
|
+
"schemaVersion": 1,
|
|
45
|
+
"organizations": [
|
|
46
|
+
{
|
|
47
|
+
"schemaVersion": "dsh-oidc/v1alpha1",
|
|
48
|
+
"id": "example-gateway",
|
|
49
|
+
"displayName": "示例模型网关",
|
|
50
|
+
"auth": {
|
|
51
|
+
"discoveryUrl": "https://gateway.example.org/.well-known/litellm-cli-auth",
|
|
52
|
+
"expectedIssuer": "https://gateway.example.org"
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
]
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
| 字段 | 如何填写 |
|
|
60
|
+
| --- | --- |
|
|
61
|
+
| `id` | 本机唯一且稳定的机构标识;多个机构使用不同值。 |
|
|
62
|
+
| `displayName` | 账户菜单中显示的机构名称。 |
|
|
63
|
+
| `auth.discoveryUrl` | 完整发现文档 URL,由管理员提供。 |
|
|
64
|
+
| `auth.expectedIssuer` | 预期的服务签发方,建议填写,并与发现文档中的 issuer 一致。 |
|
|
65
|
+
|
|
66
|
+
保存后从托盘完全退出 EduWork,再重新启动。只关闭窗口通常不会退出进程。
|
|
67
|
+
|
|
68
|
+
模型 API 地址由校验后的 issuer 追加 `/v1` 得到,保留部署路径前缀;不要另填 `provider.baseURL`。LiteLLM 会动态注册本次登录所需的 Client ID,无需手工填写固定 `clientId`、`client_secret` 或 scope,也不要同时配置 `oidc`、`keyBinding`。
|
|
69
|
+
|
|
70
|
+
正式部署使用 HTTPS。本机开发只有在机构条目中显式设置 `allowInsecureDevelopment: true`(与 `auth` 同级)才允许 loopback HTTP,不能用它连接任意明文远程地址。密码、Token 和上游 Key 均不应写入客户端配置。
|
|
71
|
+
|
|
72
|
+
其他客户端开发者可使用[单个 Profile 示例](../../examples/litellm.enterprise-profile.example.json)和[桌面宿主指南](../desktop-host.md),复用同一授权与模型模块;桌面安装用户无需自行装配 Host。
|
|
73
|
+
|
|
74
|
+
## 3. 登录并使用模型
|
|
75
|
+
|
|
76
|
+
1. 在 EduWork 账户菜单选择已配置的机构,发起登录;保持客户端运行。
|
|
77
|
+
2. 系统浏览器打开 LiteLLM 登录与授权页面。完成账号登录;网关要求选择团队时,选择有相应模型权限的团队并同意授权。
|
|
78
|
+
3. 浏览器返回本机回调页面,确认登录完成后回到 EduWork。
|
|
79
|
+
4. 在模型选择器中选择该机构的模型,发送一条简短消息确认真实模型响应。
|
|
80
|
+
|
|
81
|
+
`127.0.0.1` 回调是 EduWork 在用户电脑上临时监听的地址,不是 LiteLLM 服务器地址。浏览器必须在运行客户端的同一台电脑上完成回调;不要收藏或重复打开旧授权链接。
|
|
82
|
+
|
|
83
|
+
客户端自动读取当前授权的 `/v1/models`,请求使用 Access Token,并在临近到期时刷新。重启后通过本机受保护存储恢复授权。退出登录会清理本地会话并尝试撤销 Refresh Token;Access Token 的剩余有效期由服务端控制。
|
|
84
|
+
|
|
85
|
+
模型授权和计费仍由 LiteLLM 的用户及团队配置决定,客户端不会给账号增加权限。此接入不提供统一配额面板。模型能力取自目录和管理员核实的配置;目录只有模型 ID 时,客户端按文本模型处理,不根据名称猜测图像或思考能力。能力补充方式见 [Profile 配置](../enterprise-profile.md)。
|
|
86
|
+
|
|
87
|
+
## 4. 上线前验收
|
|
88
|
+
|
|
89
|
+
用普通用户完成以下检查,不能只用管理员账号、模型列表或 mock 响应替代真实调用:
|
|
90
|
+
|
|
91
|
+
| 检查 | 预期结果 |
|
|
92
|
+
| --- | --- |
|
|
93
|
+
| 登录、拒绝授权、重新登录 | 成功或拒绝状态明确,旧回调不能完成新登录。 |
|
|
94
|
+
| 模型目录与真实对话 | 只出现获授权的模型,能收到真实上游返回的内容。 |
|
|
95
|
+
| 流式调用 | 实际对话持续接收内容并正常结束;代理不缓冲整个 SSE。 |
|
|
96
|
+
| 使用中刷新与重启 | 到期刷新后可继续请求,重启后可恢复登录;无需复制 Token。 |
|
|
97
|
+
| 用户 / 团队隔离 | 受限用户看不到也不能调用未授权模型。 |
|
|
98
|
+
| 退出 | 本地不再能发起机构模型请求,已撤销的 Refresh Token 不能恢复授权。 |
|
|
99
|
+
|
|
100
|
+
测试环境可缩短 Token 有效期验证刷新;若通过测试工具模拟临近到期,应注明测试方式。不要把一次登录成功视为刷新已通过,也不要把真实网关加 mock 上游视为真实模型验收。
|
|
101
|
+
|
|
102
|
+
## 5. 常见问题
|
|
103
|
+
|
|
104
|
+
| 现象 | 排查方向 |
|
|
105
|
+
| --- | --- |
|
|
106
|
+
| 发现入口返回 404 或 HTML | 检查 LiteLLM 版本、公开路由和代理转发;应返回 native contract 1 JSON。 |
|
|
107
|
+
| issuer / endpoint 校验失败 | 核对 `PROXY_BASE_URL`、公开 HTTPS 地址和 `expectedIssuer`;修正部署配置后重新登录。 |
|
|
108
|
+
| 浏览器显示 `127.0.0.1` 拒绝连接 | 确认客户端仍在运行、浏览器与客户端在同一电脑,并从账户菜单发起新登录。 |
|
|
109
|
+
| 登录成功但模型列表为空或调用返回 403 | 核对用户、所选团队及模型权限;登录不等于获得全部模型权限。 |
|
|
110
|
+
| 换码、刷新失败或请求返回 401 | 检查令牌有效期、网关账号状态和服务日志;轮换 / 撤销在多副本部署中需共享 Redis。 |
|
|
111
|
+
| 提示不支持某个思考档位或输入类型 | 按当前目录支持的能力调用;不要强制传入模型不支持的 `reasoningEffort` 或附件。 |
|
|
112
|
+
| 流式内容最后一次性出现 | 检查反向代理的 SSE 缓冲和连接超时。 |
|
|
113
|
+
|
|
114
|
+
提供问题报告时,记录版本、发生阶段、HTTP 状态与已脱敏错误;不要附带授权码、Token 或完整回调 URL。更详细的交互字段见[网关认证协议参考](README.md)。
|