OAuth 2.0 接入文档
编程指南开放平台提供 OAuth 2.0 授权登录能力,允许第三方网站引导用户使用编程指南账号进行登录,获取用户基本信息。
简介
编程指南 OAuth 2.0 授权登录采用标准的 Authorization Code(授权码)模式。 第三方应用接入后,用户可以在你的网站上通过编程指南账号一键登录,无需再次注册。
授权成功后,你的应用可以获取到以下用户信息:
- 用户唯一标识(uid)
- 用户昵称(nickname)
- 用户头像(avatar)
- 用户简介(desc)
术语说明
| 术语 | 说明 |
|---|---|
client_id | 应用唯一标识,创建应用后获得 |
client_secret | 应用密钥,创建应用时获得(仅显示一次),用于后端换取 token |
redirect_uri | 授权回调地址,用户授权成功后跳转的地址 |
authorization_code | 授权码(code),用户同意授权后生成,有效期 5 分钟,一次性使用 |
access_token | 访问令牌,调用接口的凭证,有效期 2 小时 |
refresh_token | 刷新令牌,用于续期 access_token,有效期 30 天 |
scope | 授权范围,当前支持 user_info(获取用户基本信息) |
授权流程
整体流程
第一步:引导用户授权
在你的网站登录页面放置「使用编程指南登录」按钮,用户点击后跳转到编程指南授权页面。
该接口为浏览器跳转,无需设置请求头。
| 字段 | 类型 | 必填 | 描述 |
|---|---|---|---|
client_id | string | 是 | 应用唯一标识 |
redirect_uri | string | 是 | 授权回调地址,需与创建应用时填写的一致,需做 URL 编码 |
response_type | string | 是 | 固定值 code |
scope | string | 是 | 授权范围,固定值 user_info |
state | string | 推荐 | 随机字符串,用于防止 CSRF 攻击,授权完成后会原样返回 |
https://code-guide.vip/oauth/consent?client_id=your_client_id&redirect_uri=https%3A%2F%2Fyoursite.com%2Fcallback&response_type=code&scope=user_info&state=random_string该接口为浏览器跳转,用户同意授权后会重定向到你的 redirect_uri,并在 URL 中携带以下参数:
| 字段 | 类型 | 描述 |
|---|---|---|
code | string | 授权码,有效期 5 分钟,一次性使用 |
state | string | 你传入的 state 参数,原样返回 |
https://yoursite.com/callback?code=AUTHORIZATION_CODE&state=random_stringhttps://yoursite.com/callback?error=access_denied&state=random_string第二步:获取授权码
用户在编程指南授权页同意授权后,浏览器会被重定向到你填写的 redirect_uri,并携带 code 和 state 参数。
| 字段 | 类型 | 描述 |
|---|---|---|
code | string | 授权码,有效期 5 分钟,一次性使用。获取后需立即在服务端换取 access_token |
state | string | 第一步传入的 state 参数,原样返回,用于防止 CSRF 攻击 |
error | string | 错误码(仅用户拒绝授权时返回),值为 access_denied |
https://yoursite.com/callback?code=AUTHORIZATION_CODE&state=random_stringhttps://yoursite.com/callback?error=access_denied&state=random_string// 在你的 callback 页面解析回调参数
const params = new URLSearchParams(window.location.search);
const code = params.get('code');
const state = params.get('state');
const error = params.get('error');
// 验证 state 防止 CSRF
const savedState = sessionStorage.getItem('oauth_state');
if (state !== savedState) {
alert('安全验证失败');
return;
}
if (error) {
console.log('用户拒绝授权:', error);
return;
}
if (code) {
// 将 code 发送到你的后端换取 token
fetch('/api/auth/code-guide/callback', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ code, state })
})
.then(res => res.json())
.then(data => console.log('登录成功:', data));
}第三步:获取访问令牌
在你的服务端,使用授权码 code 换取 access_token。
| 字段 | 类型 | 描述 |
|---|---|---|
Content-Type | string | 请求消息类型,固定值:application/x-www-form-urlencoded |
| 字段 | 类型 | 必填 | 描述 |
|---|---|---|---|
grant_type | string | 是 | 固定值 authorization_code |
code | string | 是 | 上一步获取的授权码 |
client_id | string | 是 | 应用唯一标识 |
client_secret | string | 是 | 应用密钥 |
redirect_uri | string | 是 | 授权回调地址,需与第一步一致 |
curl -X POST https://api.code-guide.autogptai.club/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code" \
-d "code=AUTHORIZATION_CODE" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET" \
-d "redirect_uri=https://yoursite.com/callback"| 字段 | 类型 | 描述 |
|---|---|---|
code | number | 返回码,1 表示成功,0 表示失败 |
msg | string | 返回信息 |
data | object | 返回数据对象 |
└ access_token | string | 访问令牌,有效期 2 小时 |
└ token_type | string | 令牌类型,固定值 Bearer |
└ expires_in | number | 过期时间,单位:秒(默认 7200) |
└ refresh_token | string | 刷新令牌,有效期 30 天 |
└ scope | string | 授权范围 |
{
"code": 1,
"msg": "success",
"data": {
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 7200,
"refresh_token": "a1b2c3d4e5f6...",
"scope": "user_info"
}
}{
"code": 0,
"msg": "invalid authorization code",
"data": null
}第四步:获取用户信息
使用 access_token 调用以下接口获取用户基本信息。
| 字段 | 类型 | 描述 |
|---|---|---|
Authorization | string | 授权 Access-Token,格式:Bearer {access_token},获取方法见第三步 |
该接口无需请求参数,仅通过 Header 中的 Access-Token 鉴权。
curl https://api.code-guide.autogptai.club/oauth/userinfo \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"| 字段 | 类型 | 描述 |
|---|---|---|
code | number | 返回码,1 表示成功,0 表示失败 |
msg | string | 返回信息 |
data | object | 用户信息对象 |
└ uid | number | 用户唯一标识 |
└ nickname | string | 用户昵称 |
└ avatar | string | 用户头像 URL |
└ desc | string | 用户个人简介 |
{
"code": 1,
"msg": "success",
"data": {
"uid": 10001,
"nickname": "张三",
"avatar": "https://xxx/avatar.jpg",
"desc": "全栈开发者"
}
}{
"code": 0,
"msg": "invalid or expired access_token",
"data": null
}API 参考
所有 API 的基础地址为 https://api.code-guide.autogptai.club。 响应格式统一为:{ "code": 1, "msg": "success", "data": ... },其中 code=1 表示成功,code=0 表示失败。
获取 Access Token
| 字段 | 类型 | 描述 |
|---|---|---|
Content-Type | string | 请求消息类型,固定值:application/x-www-form-urlencoded |
| 字段 | 类型 | 必填 | 描述 |
|---|---|---|---|
grant_type | string | 是 | 固定值 authorization_code |
code | string | 是 | 用户授权后获取的授权码,有效期 5 分钟,一次性使用 |
client_id | string | 是 | 应用唯一标识 |
client_secret | string | 是 | 应用密钥 |
redirect_uri | string | 是 | 授权回调地址,需与第一步一致 |
curl -X POST https://api.code-guide.autogptai.club/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code" \
-d "code=AUTHORIZATION_CODE" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET" \
-d "redirect_uri=https://yoursite.com/callback"| 字段 | 类型 | 描述 |
|---|---|---|
code | number | 返回码,1 表示成功,0 表示失败 |
msg | string | 返回信息 |
data | object | 返回数据对象 |
└ access_token | string | 访问令牌,有效期 2 小时 |
└ token_type | string | 令牌类型,固定值 Bearer |
└ expires_in | number | 过期时间,单位:秒(默认 7200) |
└ refresh_token | string | 刷新令牌,有效期 30 天 |
└ scope | string | 授权范围 |
{
"code": 1,
"msg": "success",
"data": {
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 7200,
"refresh_token": "a1b2c3d4e5f6...",
"scope": "user_info"
}
}{
"code": 0,
"msg": "invalid authorization code",
"data": null
}获取用户信息
| 字段 | 类型 | 描述 |
|---|---|---|
Authorization | string | 授权 Access-Token,格式:Bearer {access_token},获取方法见接口【获取 Access Token】 |
该接口无需请求参数,仅通过 Header 中的 Access-Token 鉴权。
curl https://api.code-guide.autogptai.club/oauth/userinfo \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"| 字段 | 类型 | 描述 |
|---|---|---|
code | number | 返回码,1 表示成功,0 表示失败 |
msg | string | 返回信息 |
data | object | 用户信息对象 |
└ uid | number | 用户唯一标识 |
└ nickname | string | 用户昵称 |
└ avatar | string | 用户头像 URL |
└ desc | string | 用户个人简介 |
{
"code": 1,
"msg": "success",
"data": {
"uid": 10001,
"nickname": "张三",
"avatar": "https://xxx/avatar.jpg",
"desc": "全栈开发者"
}
}{
"code": 0,
"msg": "invalid or expired access_token",
"data": null
}刷新 Access Token
access_token 过期后,使用 refresh_token 获取新的 access_token,无需用户重新授权。
| 字段 | 类型 | 描述 |
|---|---|---|
Content-Type | string | 请求消息类型,固定值:application/x-www-form-urlencoded |
| 字段 | 类型 | 必填 | 描述 |
|---|---|---|---|
refresh_token | string | 是 | 之前获取的 refresh_token |
client_id | string | 是 | 应用唯一标识 |
client_secret | string | 是 | 应用密钥 |
curl -X POST https://api.code-guide.autogptai.club/oauth/token/refresh \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "refresh_token=YOUR_REFRESH_TOKEN" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET"| 字段 | 类型 | 描述 |
|---|---|---|
code | number | 返回码,1 表示成功,0 表示失败 |
msg | string | 返回信息 |
data | object | 返回数据对象 |
└ access_token | string | 新的访问令牌,有效期 2 小时 |
└ token_type | string | 令牌类型,固定值 Bearer |
└ expires_in | number | 过期时间,单位:秒(默认 7200) |
└ refresh_token | string | 新的刷新令牌(滚动刷新),有效期 30 天 |
└ scope | string | 授权范围 |
{
"code": 1,
"msg": "success",
"data": {
"access_token": "eyJhbGciOiJIUzI1NiIs...(new)",
"token_type": "Bearer",
"expires_in": 7200,
"refresh_token": "x9y8z7w6v5u4...(new)",
"scope": "user_info"
}
}{
"code": 0,
"msg": "invalid or expired refresh_token",
"data": null
}撤销令牌
当用户退出登录或解除绑定时,应主动撤销令牌。
| 字段 | 类型 | 描述 |
|---|---|---|
Content-Type | string | 请求消息类型,固定值:application/x-www-form-urlencoded |
| 字段 | 类型 | 必填 | 描述 |
|---|---|---|---|
token | string | 是 | 要撤销的令牌(access_token 或 refresh_token) |
client_id | string | 是 | 应用唯一标识 |
client_secret | string | 是 | 应用密钥 |
curl -X POST https://api.code-guide.autogptai.club/oauth/token/revoke \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "token=ACCESS_TOKEN_OR_REFRESH_TOKEN" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET"| 字段 | 类型 | 描述 |
|---|---|---|
code | number | 返回码,1 表示成功,0 表示失败 |
msg | string | 返回信息 |
data | null | 该接口无返回数据 |
{
"code": 1,
"msg": "success",
"data": null
}{
"code": 0,
"msg": "invalid token",
"data": null
}快速开始
创建应用
- 登录编程指南,进入 开放平台 → 开发者中心
- 点击「创建应用」,填写应用名称、Logo、简介和回调地址
- 创建成功后,妥善保存 Client ID 和 Client Secret(Secret 仅显示一次)
- 在你的网站登录页添加「使用编程指南登录」按钮
前端集成示例
在你的登录页面添加按钮,点击后跳转授权页:
<!-- 编程指南登录按钮 -->
<button onclick="loginWithCodeGuide()">使用编程指南登录</button>
<script>
function loginWithCodeGuide() {
const clientId = 'YOUR_CLIENT_ID';
const redirectUri = encodeURIComponent('https://yoursite.com/callback');
const state = Math.random().toString(36).substring(2);
// 保存 state 到 sessionStorage,回调时验证
sessionStorage.setItem('oauth_state', state);
window.location.href =
'https://code-guide.vip/oauth/consent' +
'?client_id=' + clientId +
'&redirect_uri=' + redirectUri +
'&response_type=code' +
'&scope=user_info' +
'&state=' + state;
}
</script>在回调页面处理授权结果:
// callback 页面
const params = new URLSearchParams(window.location.search);
const code = params.get('code');
const state = params.get('state');
const error = params.get('error');
// 验证 state 防止 CSRF
const savedState = sessionStorage.getItem('oauth_state');
if (state !== savedState) {
alert('安全验证失败');
return;
}
if (error) {
// 用户拒绝授权
console.log('授权被拒绝:', error);
return;
}
if (code) {
// 将 code 发送到你的后端换取 token
fetch('/api/auth/code-guide/callback', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ code, state })
})
.then(res => res.json())
.then(data => {
// 登录成功,保存用户信息
console.log('登录成功:', data);
});
}后端集成示例
以 Node.js(Express)为例:
const express = require('express');
const axios = require('axios');
const app = express();
const CLIENT_ID = 'your_client_id';
const CLIENT_SECRET = 'your_client_secret';
const REDIRECT_URI = 'https://yoursite.com/callback';
const API_BASE = 'https://api.code-guide.autogptai.club';
app.use(express.json());
// 处理回调
app.post('/api/auth/code-guide/callback', async (req, res) => {
const { code } = req.body;
try {
// 第一步:用 code 换取 access_token
const tokenRes = await axios.post(
API_BASE + '/oauth/token',
new URLSearchParams({
grant_type: 'authorization_code',
code,
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
redirect_uri: REDIRECT_URI
}).toString(),
{ headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }
);
const { access_token, refresh_token } = tokenRes.data.data;
// 第二步:用 access_token 获取用户信息
const userRes = await axios.get(API_BASE + '/oauth/userinfo', {
headers: { Authorization: 'Bearer ' + access_token }
});
const userInfo = userRes.data.data;
// 第三步:在你的系统中查找或创建用户,生成登录态
// ...
res.json({
success: true,
user: userInfo,
access_token,
refresh_token
});
} catch (error) {
console.error('OAuth 回调处理失败:', error);
res.status(500).json({ success: false, message: '登录失败' });
}
});
app.listen(3000);常见问题
Q:code 过期了怎么办?
授权码(code)有效期为 5 分钟,且只能使用一次。过期后需要引导用户重新授权获取新的 code。
Q:access_token 过期了怎么办?
access_token 有效期为 2 小时。过期后使用 refresh_token 调用 /oauth/token/refresh 接口获取新的 access_token,无需用户重新授权。
Q:refresh_token 也过期了怎么办?
refresh_token 有效期为 30 天。过期后需要引导用户重新授权。
Q:redirect_uri 必须完全一致吗?
是的。授权请求中的 redirect_uri 必须与在开发者中心创建应用时填写的回调地址完全匹配,否则授权将失败。
Q:可以在前端直接用 code 换 token 吗?
不可以。换取 token 需要使用 client_secret,该密钥不能暴露在前端代码中。请在你的服务端完成 code 换 token 的操作。
Q:如何保证安全性?
- 始终使用
state参数防止 CSRF 攻击 - client_secret 只在服务端使用,不要暴露到前端
- 使用 HTTPS 传输所有请求
- 不再使用的令牌应主动撤销
更新日志
2026-03-20
- 发布 OAuth 2.0 授权登录 v1.0
- 支持 Authorization Code 授权码模式
- 支持获取用户基本信息(uid、昵称、头像、简介)
- 提供 access_token 刷新和撤销能力
如有疑问,请在社区发帖或联系管理员。
© 2026 编程指南开放平台