Skip to content

OIDC 标准端点

Code Bird Cloud 实现了 OpenID Connect 1.0 和 OAuth 2.1 标准协议。本文档描述所有 OIDC 标准端点的使用方式。

OIDC 端点遵循标准协议规范,令牌使用 ES256(ECDSA P-256)算法签名。


发现端点

GET /.well-known/openid-configuration

返回 OpenID Connect 发现文档,包含所有 OIDC 端点的 URL 和服务器支持的特性。

请求示例:

bash
curl -X GET https://your-domain/.well-known/openid-configuration

成功响应:

json
{
  "issuer": "https://your-domain",
  "authorization_endpoint": "https://your-domain/oidc/authorize",
  "token_endpoint": "https://your-domain/oidc/token",
  "userinfo_endpoint": "https://your-domain/oidc/userinfo",
  "revocation_endpoint": "https://your-domain/oidc/revoke",
  "end_session_endpoint": "https://your-domain/oidc/end-session",
  "jwks_uri": "https://your-domain/.well-known/jwks.json",
  "scopes_supported": [
    "openid",
    "profile",
    "email",
    "phone",
    "offline_access",
    "urn:codebird:scope:organizations",
    "urn:codebird:scope:organization_roles"
  ],
  "response_types_supported": [
    "code"
  ],
  "response_modes_supported": [
    "query",
    "fragment"
  ],
  "grant_types_supported": [
    "authorization_code",
    "refresh_token",
    "client_credentials"
  ],
  "subject_types_supported": [
    "public"
  ],
  "id_token_signing_alg_values_supported": [
    "ES256"
  ],
  "token_endpoint_auth_methods_supported": [
    "client_secret_basic",
    "client_secret_post",
    "none"
  ],
  "code_challenge_methods_supported": [
    "S256"
  ],
  "claims_supported": [
    "sub",
    "iss",
    "aud",
    "exp",
    "iat",
    "name",
    "email",
    "email_verified",
    "phone_number",
    "phone_number_verified",
    "picture",
    "username",
    "organizations",
    "organization_roles",
    "organization_id",
    "organization_is_admin"
  ]
}

JSON Web Key Set

GET /.well-known/jwks.json

返回当前所有活跃的签名公钥(JSON Web Key Set),用于验证 ID Token 和 Access Token 的签名。

请求示例:

bash
curl -X GET https://your-domain/.well-known/jwks.json

成功响应:

json
{
  "keys": [
    {
      "kty": "EC",
      "crv": "P-256",
      "kid": "sk_001",
      "x": "f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU",
      "y": "x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0",
      "use": "sig",
      "alg": "ES256"
    }
  ]
}

说明: 依赖方应定期(建议每小时)刷新 JWKS 缓存,以获取最新的密钥信息。密钥轮换后,旧密钥仍会在一段时间内保留在 JWKS 中。


授权端点

GET /oidc/authorize

发起 OIDC 授权请求。此端点为浏览器重定向端点,不直接返回 JSON。

查询参数:

参数类型必填说明
client_idstring应用的 Client ID
redirect_uristring授权回调地址(需在应用配置中注册)
response_typestring固定为 code
scopestring请求的权限范围(空格分隔)
statestring推荐防止 CSRF 的随机字符串
code_challengestring推荐PKCE 挑战码(Base64url 编码的 SHA256 哈希)
code_challenge_methodstring推荐PKCE 方法,固定为 S256
promptstring交互模式:login(强制登录)、consent(强制同意)

支持的 Scope:

Scope说明
openid必填,表示 OIDC 请求,响应中包含 ID Token
profile获取用户基本信息(name、username、picture)
email获取用户邮箱信息(email、email_verified)
phone获取用户手机号信息(phone_number、phone_number_verified)
offline_access请求 Refresh Token
urn:codebird:scope:organizations获取用户所属的组织 ID 列表
urn:codebird:scope:organization_roles获取用户在各组织中的角色信息

请求示例:

https://your-domain/oidc/authorize?
  client_id=cbc_app_x7k9m2n4p1&
  redirect_uri=https://app.example.com/callback&
  response_type=code&
  scope=openid profile email offline_access&
  state=random_state_string&
  code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM&
  code_challenge_method=S256

成功行为:

浏览器会被重定向到登录页面。用户完成登录后,浏览器会被重定向到 redirect_uri,携带授权码:

https://app.example.com/callback?code=abc123&state=random_state_string

错误行为:

如果参数有误,浏览器会被重定向到 redirect_uri,携带错误信息:

https://app.example.com/callback?error=invalid_request&error_description=Invalid+redirect_uri

令牌端点

POST /oidc/token

用授权码、刷新令牌或客户端凭证交换访问令牌。

请求头:

Content-Type: application/x-www-form-urlencoded

认证方式(二选一):

  1. Basic 认证: Authorization: Basic base64(client_id:client_secret)
  2. 请求体传参: 在请求体中包含 client_idclient_secret

授权码模式(Authorization Code)

请求参数:

参数类型必填说明
grant_typestring固定为 authorization_code
codestring授权码
redirect_uristring需与授权请求中的一致
code_verifierstring条件必填PKCE 验证码(如果授权请求中使用了 code_challenge)
client_idstring条件必填客户端 ID(如果未使用 Basic 认证)
client_secretstring条件必填客户端密钥(如果未使用 Basic 认证,且非公共客户端)

请求示例:

bash
curl -X POST https://your-domain/oidc/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code" \
  -d "code=abc123" \
  -d "redirect_uri=https://app.example.com/callback" \
  -d "code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk" \
  -d "client_id=cbc_app_x7k9m2n4p1" \
  -d "client_secret=cbc_secret_a1b2c3d4e5f6g7h8i9j0"

成功响应:

json
{
  "access_token": "eyJhbGciOiJFUzI1NiIs...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "rt_abc123def456...",
  "id_token": "eyJhbGciOiJFUzI1NiIs...",
  "scope": "openid profile email offline_access"
}

刷新令牌模式(Refresh Token)

请求参数:

参数类型必填说明
grant_typestring固定为 refresh_token
refresh_tokenstring刷新令牌
organization_idstring组织 ID(获取组织级 Token)
resourcestring资源标识符(与 organization_id 配合使用)
client_idstring条件必填客户端 ID
client_secretstring条件必填客户端密钥

请求示例:

bash
curl -X POST https://your-domain/oidc/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=refresh_token" \
  -d "refresh_token=rt_abc123def456..." \
  -d "client_id=cbc_app_x7k9m2n4p1" \
  -d "client_secret=cbc_secret_a1b2c3d4e5f6g7h8i9j0"

成功响应:

json
{
  "access_token": "eyJhbGciOiJFUzI1NiIs...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "rt_new_xyz789...",
  "id_token": "eyJhbGciOiJFUzI1NiIs...",
  "scope": "openid profile email offline_access"
}

客户端凭证模式(Client Credentials)

用于 MachineToMachine 类型应用的服务间通信。

请求参数:

参数类型必填说明
grant_typestring固定为 client_credentials
resourcestring请求访问的资源标识符
scopestring请求的权限范围
organization_idstring组织 ID(获取组织级 Token)
client_idstring条件必填客户端 ID
client_secretstring条件必填客户端密钥

请求示例:

bash
curl -X POST https://your-domain/oidc/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials" \
  -d "resource=https://api.bookstore.com" \
  -d "scope=read:books write:books" \
  -d "client_id=cbc_app_m2m_001" \
  -d "client_secret=cbc_secret_m2m_abc123"

成功响应:

json
{
  "access_token": "eyJhbGciOiJFUzI1NiIs...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "read:books write:books"
}

注意: 客户端凭证模式不返回 refresh_tokenid_token


令牌错误响应

json
{
  "error": "invalid_grant",
  "error_description": "Authorization code has expired or has been used"
}

常见错误码:

错误码说明
invalid_request请求参数缺失或格式错误
invalid_client客户端认证失败
invalid_grant授权码/刷新令牌无效或已过期
unauthorized_client客户端无权使用此授权类型
unsupported_grant_type不支持的授权类型

令牌撤销端点

POST /oidc/revoke

撤销访问令牌或刷新令牌。

请求头:

Content-Type: application/x-www-form-urlencoded

请求参数:

参数类型必填说明
tokenstring要撤销的令牌
token_type_hintstring令牌类型提示:access_tokenrefresh_token
client_idstring条件必填客户端 ID
client_secretstring条件必填客户端密钥

请求示例:

bash
curl -X POST https://your-domain/oidc/revoke \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "token=rt_abc123def456..." \
  -d "token_type_hint=refresh_token" \
  -d "client_id=cbc_app_x7k9m2n4p1" \
  -d "client_secret=cbc_secret_a1b2c3d4e5f6g7h8i9j0"

成功响应:

HTTP/1.1 200 OK

根据 RFC 7009,无论令牌是否有效,撤销端点始终返回 200。


用户信息端点

GET /oidc/userinfoPOST /oidc/userinfo

获取当前认证用户的信息。返回的字段取决于授权时请求的 Scope。

/oidc/userinfo 返回的是基于当前 Access Token 的标准 OIDC 用户 claims, 适合轻量用户展示与标准协议对接。 如果你需要实时的组织关系、应用信息或最新管理员状态,请改用 GET /api/session/context

请求头:

Authorization: Bearer <access_token>

请求示例:

bash
curl -X GET https://your-domain/oidc/userinfo \
  -H "Authorization: Bearer eyJhbGciOiJFUzI1NiIs..."

成功响应(scope: openid profile email phone):

json
{
  "sub": "usr_abc123",
  "username": "john_doe",
  "name": "John Doe",
  "picture": "https://example.com/avatar.png",
  "email": "john@example.com",
  "email_verified": true,
  "phone_number": "+8613800138000",
  "phone_number_verified": false
}

Scope 与返回字段的对应关系:

Scope返回字段
openidsub
profileusernamenamepicturegenderupdated_at
emailemailemail_verified
phonephone_numberphone_number_verified
urn:codebird:scope:organizationsorganizations(用户所属组织 ID 数组)
urn:codebird:scope:organization_rolesorganization_roles(各组织角色信息,格式为 ["org_id:role_name"]

当 Access Token 具有组织上下文(例如授权请求或 refresh token 换取组织级 Token 时指定了 organization_id), /oidc/userinfo 还会额外返回:

字段类型说明
organization_idstring当前组织上下文的组织 ID
organization_is_adminboolean当前用户在该组织下是否为组织管理员

示例:

json
{
  "sub": "usr_abc123",
  "username": "john_doe",
  "organization_id": "org_123",
  "organizations": ["org_123"],
  "organization_roles": ["org_123:member"],
  "organization_is_admin": true
}

说明:

  • organization_roles 当前标准格式为字符串数组,每项格式为 org_id:role_name
  • organization_roles 只表示角色模板名称,不再代表组织管理员身份
  • 当前登录用户在当前组织下是否为组织管理员,请读取 organization_is_admin

错误响应(令牌无效):

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer error="invalid_token", error_description="The access token is expired or invalid"

结束会话端点

GET /oidc/end-session

结束用户的登录会话(登出)。

查询参数:

参数类型必填说明
id_token_hintstring推荐用户的 ID Token,用于确定要登出的会话
post_logout_redirect_uristring登出后的重定向地址
statestring状态参数,会原样传回到重定向地址

请求示例:

https://your-domain/oidc/end-session?
  id_token_hint=eyJhbGciOiJFUzI1NiIs...&
  post_logout_redirect_uri=https://app.example.com&
  state=logout_state

成功行为:

浏览器重定向到指定的 post_logout_redirect_uri

https://app.example.com?state=logout_state

ID Token 结构

ID Token 是一个 JWT,包含以下声明(Claims):

json
{
  "iss": "https://your-domain",
  "sub": "usr_abc123",
  "aud": "cbc_app_x7k9m2n4p1",
  "exp": 1718500800,
  "iat": 1718497200,
  "at_hash": "HK6E_P6Dh8Y93mRNtsDB1Q",
  "name": "John Doe",
  "username": "john_doe",
  "email": "john@example.com",
  "email_verified": true,
  "picture": "https://example.com/avatar.png"
}

标准声明:

声明说明
iss签发者(Issuer),即 Code Bird Cloud 的 Base URL
sub主体(Subject),即用户 ID
aud受众(Audience),即 Client ID
exp过期时间(Unix 时间戳)
iat签发时间(Unix 时间戳)
at_hashAccess Token 的哈希值

集成指南

推荐的授权流程(PKCE + Authorization Code)

1. 生成 code_verifier(随机字符串,43-128 字符)
2. 计算 code_challenge = BASE64URL(SHA256(code_verifier))
3. 重定向到 /oidc/authorize(携带 code_challenge)
4. 用户完成登录
5. 获取授权码(从回调 URL 中提取 code 参数)
6. POST /oidc/token 交换令牌(携带 code_verifier)
7. 验证 ID Token(使用 JWKS 公钥验证 ES256 签名)
8. 使用 Access Token 访问受保护资源

安全建议

  • 始终使用 PKCE: 即使是机密客户端也建议使用 PKCE。
  • 验证 state 参数: 防止 CSRF 攻击。
  • 验证 ID Token: 验证签名、iss、aud、exp 等声明。
  • 安全存储令牌: 不要将令牌存储在 localStorage 中,推荐使用 HttpOnly Cookie 或内存存储。
  • 及时刷新令牌: 在 Access Token 过期前使用 Refresh Token 获取新令牌。
  • 登出时撤销令牌: 调用 /oidc/revoke 撤销 Refresh Token。

Released under the MIT License.