OAuth2.0 接入文档
CZL Connect 提供标准 OAuth 2.0 Authorization Code 授权流程。
在 CZL Connect 后台,客户端认证方式统一为两类:
secretnone
其中 secret 客户端在协议层同时兼容 client_secret_basic 与 client_secret_post 两种标准传参方式。
当客户端认证方式为 none 时,授权码交换必须使用 PKCE。
适用范围
| 客户端类型 | 推荐认证方式 |
|---|---|
| 服务端 Web 应用 | secret |
| 桌面端应用 | none + PKCE |
| 移动端应用 | none + PKCE |
| SPA / 浏览器前端 | none + PKCE |
服务端应用可以安全保存 client_secret。
桌面端、移动端和浏览器前端无法将 client_secret 视为机密,应使用 PKCE。
认证方式
secret
CZL Connect 的 secret 客户端兼容以下两种标准 OAuth2 传参方式。
client_secret_basic
客户端通过 HTTP Basic 认证发送 client_id 与 client_secret。
Authorization: Basic BASE64(CLIENT_ID:CLIENT_SECRET)
client_secret_post
客户端通过 application/x-www-form-urlencoded 请求体发送 client_id 与 client_secret。
client_id=YOUR_CLIENT_ID
client_secret=YOUR_CLIENT_SECRET
none
客户端不发送 client_secret。
此模式下必须使用 PKCE。
PKCE
PKCE 适用于无法安全保存 client_secret 的客户端。
流程要求如下:
- 客户端生成高强度随机字符串
code_verifier - 客户端计算
code_challenge = BASE64URL(SHA256(code_verifier)) - 授权请求携带
code_challenge与code_challenge_method=S256 - 令牌请求携带
code_verifier
CZL Connect 当前仅支持 S256。
端点
| 端点 | URL |
|---|---|
| 授权端点 | https://connect.czl.net/oauth2/authorize |
| 令牌端点 | https://connect.czl.net/api/oauth2/token |
| 用户信息端点 | https://connect.czl.net/api/oauth2/userinfo |
| 用户邮箱端点 | https://connect.czl.net/api/oauth2/user/emails |
授权请求
基本参数
| 参数 | 必填 | 说明 |
|---|---|---|
response_type | 是 | 固定为 code |
client_id | 是 | 应用的客户端 ID |
redirect_uri | 是 | 回调地址 |
scope | 否 | 授权范围 |
state | 否 | 客户端状态参数,建议始终提供 |
upstream_providers | 否 | 限制可用上游认证方式,逗号分隔 |
prompt | 否 | none 表示静默认证,见「静默认证」章节 |
code_challenge | PKCE 时必填 | PKCE challenge |
code_challenge_method | PKCE 时必填 | 固定为 S256 |
Traditional Client
https://connect.czl.net/oauth2/authorize?
response_type=code
&client_id=YOUR_CLIENT_ID
&redirect_uri=YOUR_REDIRECT_URI
&scope=read
&state=RANDOM_STATE_VALUE
Public Client + PKCE
https://connect.czl.net/oauth2/authorize?
response_type=code
&client_id=YOUR_CLIENT_ID
&redirect_uri=YOUR_REDIRECT_URI
&scope=read
&state=RANDOM_STATE_VALUE
&code_challenge=YOUR_CODE_CHALLENGE
&code_challenge_method=S256
令牌请求
授权码换取令牌
secret 客户端: client_secret_post
POST https://connect.czl.net/api/oauth2/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=AUTHORIZATION_CODE
&client_id=YOUR_CLIENT_ID
&client_secret=YOUR_CLIENT_SECRET
&redirect_uri=YOUR_REDIRECT_URI
secret 客户端: client_secret_basic
POST https://connect.czl.net/api/oauth2/token
Content-Type: application/x-www-form-urlencoded
Authorization: Basic BASE64(YOUR_CLIENT_ID:YOUR_CLIENT_SECRET)
grant_type=authorization_code
&code=AUTHORIZATION_CODE
&redirect_uri=YOUR_REDIRECT_URI
none + PKCE
POST https://connect.czl.net/api/oauth2/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=AUTHORIZATION_CODE
&client_id=YOUR_CLIENT_ID
&redirect_uri=YOUR_REDIRECT_URI
&code_verifier=YOUR_CODE_VERIFIER
响应示例
{
"access_token": "ACCESS_TOKEN",
"token_type": "bearer",
"refresh_token": "REFRESH_TOKEN",
"expires_in": 86400,
"scope": "read"
}
刷新令牌
secret 客户端: client_secret_post
POST https://connect.czl.net/api/oauth2/token
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token
&refresh_token=REFRESH_TOKEN
&client_id=YOUR_CLIENT_ID
&client_secret=YOUR_CLIENT_SECRET
secret 客户端: client_secret_basic
POST https://connect.czl.net/api/oauth2/token
Content-Type: application/x-www-form-urlencoded
Authorization: Basic BASE64(YOUR_CLIENT_ID:YOUR_CLIENT_SECRET)
grant_type=refresh_token
&refresh_token=REFRESH_TOKEN
none
POST https://connect.czl.net/api/oauth2/token
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token
&refresh_token=REFRESH_TOKEN
&client_id=YOUR_CLIENT_ID
用户信息
请求
GET https://connect.czl.net/api/oauth2/userinfo
Authorization: Bearer ACCESS_TOKEN
响应
{
"id": 1,
"username": "zhangsan",
"nickname": "张三",
"email": "[email protected]",
"avatar": "https://example.com/avatar.png",
"groups": ["t0", "t1", "t2", "t3", "t4", "t5", "viewer", "admin"],
"upstreams": []
}
字段
| 字段 | 说明 |
|---|---|
id | 用户 ID |
username | 用户名 |
nickname | 用户昵称 |
email | 用户邮箱 |
avatar | 用户头像 URL |
groups | 用户分组数组(字符串数组),包含继承展开后的分组值 |
upstreams | 用户绑定的上游账号信息 |
用户邮箱接口
请求
GET https://connect.czl.net/api/oauth2/user/emails
Authorization: Bearer ACCESS_TOKEN
响应
[
{
"email": "[email protected]",
"verified": true,
"primary": true,
"visibility": "public"
}
]
上游认证限制
upstream_providers 用于限制授权流程中可用的上游认证方式。
https://connect.czl.net/oauth2/authorize?
response_type=code
&client_id=YOUR_CLIENT_ID
&redirect_uri=YOUR_REDIRECT_URI
&scope=read
&state=RANDOM_STATE_VALUE
&upstream_providers=discourse,github
常见取值包括:
discoursegithubgoogleqqwechat
静默认证 (prompt=none)
prompt=none 用于"打开页面自动恢复登录":用户已登录 CZL Connect 且此前授权过你的应用时,整个授权流程无任何交互,浏览器短暂跳转后带着新授权码回到 redirect_uri;无法静默完成时不展示登录页或授权页,而是立即带错误参数回跳,由你的应用决定后续动作(保持未登录,或发起一次正常的交互式授权)。
https://connect.czl.net/oauth2/authorize?
response_type=code
&client_id=YOUR_CLIENT_ID
&redirect_uri=YOUR_REDIRECT_URI
&scope=read
&state=RANDOM_STATE_VALUE
&prompt=none
失败时回跳 redirect_uri 携带 error、error_description 与原样返回的 state:
error | 含义 |
|---|---|
login_required | 用户未登录 CZL Connect |
consent_required | 用户尚未授权过此应用(首次授权必须走交互流程) |
interaction_required | 需要用户交互才能继续(如邮箱未验证、缺少要求的上游绑定) |
access_denied | 用户无权访问此应用或应用配额已满 |
使用要求:
- 必须通过顶层整页跳转发起(
location.href或服务端 302),不要使用隐藏 iframe——CZL Connect 会话 Cookie 为SameSite=Lax,iframe 内不携带 Cookie,静默认证永远返回login_required - 典型用法:应用本地会话过期时跳转一次
prompt=none,收到login_required后再决定是否展示"登录"入口 - 避免在收到错误回跳后立即再次发起
prompt=none,防止跳转循环 prompt=none不允许与其它prompt值并存
迁移到 PKCE
从传统 client_secret 模式迁移到 PKCE 时,通常只需要修改以下内容:
- 在 CZL Connect 后台将客户端认证方式改为
none - 授权请求增加
code_challenge与code_challenge_method=S256 - 令牌请求删除
client_secret - 令牌请求增加
code_verifier
用户信息接口、回调地址、scope 和授权端点不需要调整。
安全要求
client_secret仅适用于能够安全保存机密的服务端应用- 桌面端、移动端和浏览器前端不应内置
client_secret - Public Client 必须使用 PKCE
state应始终由客户端生成并校验- 客户端仍需妥善保存
access_token与refresh_token - 当前仅支持
S256