本目录包含 SEKAI Pass OpenID Connect (OIDC) 集成的各种示例代码。
特点:
- 纯 HTML + JavaScript
- 完整的 OIDC 授权码流程
- PKCE 支持(S256)
- Nonce 防重放攻击
- ID Token 解码和显示
- Discovery 和 JWKS 测试
使用方法:
# 直接在浏览器中打开
open oidc-demo.html
# 或使用简单的 HTTP 服务器
python3 -m http.server 8080
# 然后访问 http://localhost:8080/oidc-demo.html配置: 在 HTML 文件中修改配置:
const CONFIG = {
issuer: 'https://id.nightcord.de5.net',
clientId: 'demo-client', // 修改为你的 Client ID
redirectUri: window.location.href.split('?')[0],
scope: 'openid profile email'
};特点:
- 使用
openid-client标准库 - Express.js 后端
- 自动 OIDC Discovery
- Session 管理
- ID Token 验证
- 用户信息展示
安装依赖:
cd examples
npm install运行:
npm start
# 或使用 nodemon 自动重启
npm run dev访问: 打开浏览器访问 http://localhost:3000
配置:
在 oidc-client-nodejs.js 中修改配置:
const CONFIG = {
issuer: 'https://id.nightcord.de5.net',
clientId: 'demo-client', // 修改为你的 Client ID
redirectUri: 'http://localhost:3000/callback',
scope: 'openid profile email'
};特点:
- 使用
Authlib标准库 - Flask 后端
- 自动 OIDC Discovery
- PKCE S256 保护
- 模板渲染
安装依赖:
cd examples
pip install -r requirements.txt运行:
python oidc-client-python.py访问: 打开浏览器访问 http://localhost:5000
配置:
在 oidc-client-python.py 中修改配置:
CONFIG = {
'issuer': 'https://id.nightcord.de5.net',
'client_id': 'demo-client', # 修改为你的 Client ID
'redirect_uri': 'http://localhost:5000/callback',
'scope': 'openid profile email'
}特点:
- OAuth 2.1 + PKCE
- 不包含 OIDC(无 ID Token)
- 适合纯 OAuth 场景
使用方法:
open pkce-frontend.html在使用示例之前,需要在 SEKAI Pass 中注册 OAuth 应用。
注意: 应用管理 UI 尚未实现,需要通过数据库注册应用。
# 本地开发环境
npx wrangler d1 execute sekai_pass_db --local --command "
INSERT INTO applications (id, name, client_id, client_secret, redirect_uris, created_at)
VALUES (
'app-' || hex(randomblob(8)),
'Demo Application',
'demo-client-' || hex(randomblob(8)),
'secret-' || hex(randomblob(16)),
'[\"http://localhost:3000/callback\",\"http://localhost:8080/oidc-demo.html\",\"http://localhost:5000/callback\"]',
$(date +%s)000
)
RETURNING client_id, client_secret;"
# 生产环境(使用 --remote 替换 --local)
npx wrangler d1 execute sekai_pass_db --remote --command "..."记录凭据: 保存输出的 client_id 和 client_secret,在示例配置中使用。
在每个示例文件中,找到配置部分并修改:
const CONFIG = {
issuer: 'https://id.nightcord.de5.net', // OIDC 授权服务器
clientId: 'YOUR_CLIENT_ID', // 替换为你的 Client ID
redirectUri: 'YOUR_REDIRECT_URI', // 替换为你的回调 URI
scope: 'openid profile email' // 请求的权限范围
};客户端重定向用户到授权端点:
GET /oauth/authorize?
client_id=YOUR_CLIENT_ID&
redirect_uri=YOUR_REDIRECT_URI&
response_type=code&
scope=openid%20profile%20email&
code_challenge=CHALLENGE&
code_challenge_method=S256&
state=RANDOM_STATE&
nonce=RANDOM_NONCE
重要参数:
scope: 必须包含openid才能获取 ID Tokencode_challenge: PKCE 挑战码(SHA256 哈希)nonce: 防重放攻击的随机值
用户在 SEKAI Pass 登录并授权应用访问其信息。
SEKAI Pass 重定向回应用,带上授权码:
GET /callback?
code=AUTHORIZATION_CODE&
state=RANDOM_STATE
应用使用授权码交换 tokens:
POST /oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&
code=AUTHORIZATION_CODE&
client_id=YOUR_CLIENT_ID&
code_verifier=VERIFIER响应:
{
"access_token": "...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "...",
"scope": "openid profile email",
"id_token": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9..."
}ID Token 是一个 JWT,包含用户信息:
{
"iss": "https://id.nightcord.de5.net",
"sub": "user_id",
"aud": "client_id",
"exp": 1234567890,
"iat": 1234567890,
"auth_time": 1234567890,
"nonce": "random_nonce",
"name": "Display Name",
"preferred_username": "username",
"email": "user@example.com",
"email_verified": true
}所有示例都使用 PKCE (Proof Key for Code Exchange):
// 生成 code_verifier
const verifier = generateRandomString(32);
// 生成 code_challenge (SHA256)
const challenge = base64URLEncode(sha256(verifier));
// 授权请求时发送 challenge
// Token 交换时发送 verifier防止 CSRF 攻击:
// 授权前保存 state
sessionStorage.setItem('oauth_state', state);
// 回调时验证
if (params.state !== sessionStorage.getItem('oauth_state')) {
throw new Error('State mismatch');
}防止重放攻击:
// 授权前保存 nonce
sessionStorage.setItem('oidc_nonce', nonce);
// 验证 ID Token 中的 nonce
const claims = decodeJWT(idToken);
if (claims.nonce !== sessionStorage.getItem('oidc_nonce')) {
throw new Error('Nonce mismatch');
}使用 JWKS 端点获取公钥验证签名:
// 获取 JWKS
const jwks = await fetch('https://id.nightcord.de5.net/.well-known/jwks.json');
// 使用公钥验证 JWT 签名
// (使用 jose 或 jsonwebtoken 库)curl https://id.nightcord.de5.net/.well-known/openid-configuration | jqcurl https://id.nightcord.de5.net/.well-known/jwks.json | jqcurl -H "Authorization: Bearer ACCESS_TOKEN" \
https://id.nightcord.de5.net/oauth/userinfo | jq- OIDC 快速开始 - 5分钟快速开始
- OIDC 实现细节 - 完整技术文档
- OpenID Connect Core 1.0 - 官方规范
原因: 授权请求中没有包含 openid scope
解决: 确保 scope 参数包含 openid:
scope: 'openid profile email'原因: 使用了错误的公钥或密钥已轮换
解决: 从 JWKS 端点获取最新的公钥
原因: 多个标签页或会话冲突
解决: 使用 sessionStorage 而不是 localStorage
原因: 前端直接调用 token 端点
解决:
- 使用后端代理(推荐)
- 或在 SEKAI Pass 中配置 CORS(如果支持)
- 开发环境: 使用
http://localhost进行测试 - 生产环境: 必须使用 HTTPS
- Client ID: 每个应用需要唯一的 Client ID
- Redirect URI: 必须完全匹配注册的 URI
- Scope:
openid是必需的,其他 scope 可选
欢迎提交更多示例!支持的语言/框架:
- Python (Flask/Django)
- Java (Spring Boot)
- Go
- PHP
- Ruby (Rails)
- 等等...
如有问题,请查看: