首页
/ AutoGPT Platform 第三方应用 OAuth 2.0 接入指南:授权码流、PKCE、SSO 与集成向导

AutoGPT Platform 第三方应用 OAuth 2.0 接入指南:授权码流、PKCE、SSO 与集成向导

2026-09-07 19:34:44作者:明树来

本篇以 AutoGPT Platform 对外发布的 OAuth 集成指南 为骨架,结合其源码(OAuth Provider 端点OAuth 数据层)讲解如何让第三方应用安全地接入 AutoGPT Platform:既可以让应用代表用户调用 Agent 编排、Store、Integration 等 API,也可以把 AutoGPT 当作身份提供方(Identity Provider)实现 "Sign in with AutoGPT" SSO。读完你能够独立完成授权 URL 构造、PKCE 挑战码生成、授权码换 Token、Token 续期与吊销,以及引导用户完成第三方服务(GitHub、Google、Notion、Linear 等)的连接向导。

一、OAuth 在 AutoGPT Platform 中的三种应用场景

AutoGPT Platform 的 OAuth 实现是基于 OAuth 2.0 授权码模式(Authorization Code Flow)+ PKCE 的完整 Provider,官方给出的定位如下:

  • API 访问(OAuth for API Access):应用需要"代表用户"调用 AutoGPT API——例如替用户运行 Agent(Graph)、访问 Agent Store、为其管理第三方集成。相比长期有效的单把 API Key,OAuth 让权限随用户而绑定、随用户撤销而失效。
  • SSO(Sign in with AutoGPT):把 AutoGPT 当作身份提供方。当你的应用需要识别用户、但又不想自行管理密码体系时,可以让用户用已有的 AutoGPT 账号直接登录你的应用。此时只需在授权时请求 IDENTITY scope,再通过 /external-api/v1/me 拉取用户资料。
  • 两者可叠加:SSO 与 API 访问并不互斥。官方指南明确指出:在 scope 列表中同时请求 IDENTITY 与其他权限 scope,即可"既完成身份认证、又取得调用 API 的授权"。
  • Integration Setup Wizard(集成配置向导):这是一个独立的引导流程。当你的应用要求用户事先把 GitHub、Google 等第三方账号连到其 AutoGPT 账户时,可通过向导让用户一次性完成这些服务的连接配置。

OAuth 数据层 的文件头注释可以看到仓库内部对完整流程的表述:第三方应用点击 "Login with AutoGPT" → 应用重定向用户到 /auth/authorize(携带 client_idredirect_uriscopestate)→ 用户看到同意页(Consent Screen,未登录先登录)→ 用户批准后后端签发一次性授权码 → 应用以授权码换取 access/refresh token → 之后用 access token 调用外部 API。这与下文逐步操作一一对应。

二、前置条件:注册 OAuth 应用

在开始编码前,你需要在 AutoGPT Platform 侧注册一个 OAuth 应用。参照官方指南,注册后可以从平台(当前需要联系平台管理员)获得三项凭证:

凭证 说明
Client ID 应用在平台的公开标识符,出现在所有授权 URL 与 Token 请求中(示例形如 agpt_client_...
Client Secret 应用用于证明自己身份的密钥,必须妥善保管,严禁放进前端代码或提交进版本库
Registered Redirect URIs 授权完成后允许跳转回应用的回调地址白名单,一个应用可注册多个

在服务端数据结构中,每个应用还携带 grant_types(允许的授权类型)与 scopes(允许请求的权限集合)等字段,并且平台会记录应用归属的 owner_id 与启用状态 is_active,见 data/auth/oauth.py 的 OAuthApplicationInfo 模型。关于 Client Secret 的处理,数据层采取的是不落明文策略:Client Secret 使用 Scrypt 加盐哈希后存储,验证时按 client_id 查出哈希再比对,见 data/auth/oauth.py#L7-L10verify_secret 实现(data/auth/oauth.py#L139-L144)。

三、标准 OAuth 流程五步走(API 访问 / SSO 通用)

无论你接入的是 API 访问、SSO 还是两者,底层流程完全一致,唯一的区别在于请求的 scope 不同。

Step 1:把用户重定向到授权页

在用户浏览器中发起如下跳转(下述字段均为必填):

https://platform.agpt.co/auth/authorize?
  client_id={YOUR_CLIENT_ID}&
  redirect_uri=https://yourapp.com/callback&
  scope=EXECUTE_GRAPH READ_GRAPH&
  state={RANDOM_STATE_TOKEN}&
  code_challenge={PKCE_CHALLENGE}&
  code_challenge_method=S256&
  response_type=code

授权参数一览

参数 必填 说明
client_id 你的 OAuth 应用 Client ID
redirect_uri 授权完成后跳转回你的地址,必须与已注册的 URI 完全匹配
scope 空格分隔的权限列表(可用 scope 见下文与 API Guide 中的 Available Scopes 章节)
state 随机字符串,用于防 CSRF,回调时必须核对与发送值一致
code_challenge PKCE 码挑战(生成方法见下文 PKCE 章节)
code_challenge_method 必须为 S256(后端同时兼容 plain,但官方推荐且强制 PKCE)
response_type 授权码模式固定为 code

从源码侧印证:后端授权端点定义在 api/features/oauth.py 的 /authorize 路由,其请求模型 AuthorizeRequest 与上表字段一一对应,其中 response_type 仅接受 codecode_challenge 为必填、code_challenge_method 允许 S256/plain(默认 S256)——这些约束在源码层面对文档中的"必须 PKCE"做了强制。此外后端还有一个应用公开信息端点 GET /app/{client_id},用于在同意页向用户展示应用名称、描述、Logo 与允许的 scopes(见 oauth.py#L98-L130),这也是为什么注册应用时可以顺带配置展示信息。

Step 2:处理回调

用户批准(或拒绝)之后,会被重定向回你的 redirect_uri

成功回调:

https://yourapp.com/callback?code=AUTHORIZATION_CODE&state=RANDOM_STATE_TOKEN

失败回调:

https://yourapp.com/callback?error=access_denied&error_description=User%20denied%20access&state=RANDOM_STATE_TOKEN

务必核对 state:无论成功失败,都要先确认 state 与你 Step 1 发送的随机值一致,否则拒绝处理——这是防 CSRF 的关键闸门。

后端同样会在出错场景通过携带 error/error_description 参数的 redirect URL 通知客户端(源码注释见 oauth.py#L186-L200),例如发现 response_type 非法时返回 unsupported_response_type

Step 3:用授权码换 Token

拿到授权码后,在服务端(一定不能在浏览器侧)发起如下交换请求:

POST /api/oauth/token
Content-Type: application/json

{
  "grant_type": "authorization_code",
  "code": "{AUTHORIZATION_CODE}",
  "redirect_uri": "https://yourapp.com/callback",
  "client_id": "{YOUR_CLIENT_ID}",
  "client_secret": "{YOUR_CLIENT_SECRET}",
  "code_verifier": "{PKCE_VERIFIER}"
}

成功响应:

{
  "token_type": "Bearer",
  "access_token": "agpt_xt_...",
  "access_token_expires_at": "2025-01-15T12:00:00Z",
  "refresh_token": "agpt_rt_...",
  "refresh_token_expires_at": "2025-02-14T12:00:00Z",
  "scopes": ["EXECUTE_GRAPH", "READ_GRAPH"]
}

响应字段与后端 TokenResponse 模型逐一对齐(oauth.py#L66-L74)。其中:

  • 授权码是一次性使用的:兑换成功即作废,重复使用会得到 invalid_grant
  • 授权码短时有效(默认 10 分钟,见下文 Token 生命周期);
  • 回调中必须带 code_verifier,服务端会用它验证 code_challenge,从而杜绝授权码被截获后冒充的中间人风险。

关于 Token 本身的存储,数据层同样不落明文:Access/Refresh Token 以 SHA-256 摘要形式落库(确定性哈希便于按 token 直查),见 data/auth/oauth.py#L7-L10 的注释与 _hash_token 实现(data/auth/oauth.py#L39-L41)。

Step 4:携带 Token 调用 API(SSO 场景取用户信息)

把 access token 作为 Authorization: Bearer 头发送到 AutoGPT Platform 的外部 API:

GET /external-api/v1/blocks
Authorization: Bearer agpt_xt_...

SSO 场景:若你在授权时请求了 IDENTITY scope,调用 /me 即可拿到用户资料,用于在你的应用内识别并登录用户:

GET /external-api/v1/me
Authorization: Bearer agpt_xt_...

响应:

{
  "id": "user-uuid",
  "name": "John Doe",
  "email": "john@example.com",
  "timezone": "Europe/Amsterdam"
}

从实现侧看,"scope 是否够用"最终落在外部 API 的权限检查上:外部 API 各路由会调用 require_permission(APIKeyPermission.XXX) 校验令牌的 scope——例如在 api/external/v1/routes.py 中用户资料类端点要求 IDENTITY、执行/读取 Agent 图的端点分别要求 EXECUTE_GRAPHREAD_GRAPH;而集成管理端点则要求 READ_INTEGRATIONS/MANAGE_INTEGRATIONS(见 api/external/v1/integrations.py)。access token 本质上等价于一把"绑定到用户 + 限定 scope 集合"的临时密钥,因此你可以在应用里按需申请权限,而不是像 API Key 那样一把钥匙全权限。

Step 5:刷新 Token

Access Token 默认 1 小时过期(源码常量 ACCESS_TOKEN_TTL = timedelta(hours=1)data/auth/oauth.py#L46)。过期后用 refresh token 换取新 token:

POST /api/oauth/token
Content-Type: application/json

{
  "grant_type": "refresh_token",
  "refresh_token": "agpt_rt_...",
  "client_id": "{YOUR_CLIENT_ID}",
  "client_secret": "{YOUR_CLIENT_SECRET}"
}

响应:

{
  "token_type": "Bearer",
  "access_token": "agpt_xt_...",
  "access_token_expires_at": "2025-01-15T13:00:00Z",
  "refresh_token": "agpt_rt_...",
  "refresh_token_expires_at": "2025-02-14T12:00:00Z",
  "scopes": ["EXECUTE_GRAPH", "READ_GRAPH"]
}

刷新成功后通常会连带轮换 refresh token,务必用新值覆盖旧值;refresh token 过期(默认 30 天)后,则需要引导用户重新走一遍完整授权流程。

四、Integration Setup Wizard:引导用户预连第三方服务

当你的应用需要用户事先把 GitHub、Google、Slack 等账号连到其 AutoGPT 账户时(比如你的 Agent 会用到这些服务的凭证),可以借助官方独立的集成配置向导完成,无需自己重造一套第三方 OAuth 授权 UI。

跳转到向导

https://platform.agpt.co/auth/integrations/setup-wizard?
  client_id={YOUR_CLIENT_ID}&
  providers={BASE64_ENCODED_PROVIDERS}&
  redirect_uri=https://yourapp.com/callback&
  state={RANDOM_STATE_TOKEN}

参数说明

参数 必填 说明
client_id 你的 OAuth 应用 Client ID
providers Base64 编码的 JSON 数组,描述要连接哪些服务及各自请求的 scopes
redirect_uri 配置流程结束后跳回的地址
state 随机字符串,防 CSRF,回调时核对

构造 providers 参数

providers 是一个 Base64 编码后的 JSON 数组,例如:

const providers = [
  { provider: 'github', scopes: ['repo', 'read:user'] },
  { provider: 'google', scopes: ['https://www.googleapis.com/auth/calendar'] },
  { provider: 'slack' }  // Uses default scopes
];

const providersBase64 = btoa(JSON.stringify(providers));

对应实现位于前端 auth/integrations/setup-wizard 页面/auth/integrations/setup-wizard/page.tsx),它负责按清单逐个唤起各服务商的授权流程并把结果写回用户的 AutoGPT 账户。

处理向导回调

流程结束(无论成功还是用户取消)后,浏览器回到你的 redirect_uri

成功:

https://yourapp.com/callback?success=true&state=RANDOM_STATE_TOKEN

失败 / 用户取消:

https://yourapp.com/callback?success=false&state=RANDOM_STATE_TOKEN

五、Provider Scopes 参考

使用 Integration Setup Wizard 时,你需要为每个服务商明确要申请的 scopes。以下是官方给出的常见服务商清单(表格为文档原文,各服务商的完整 scope 语义以各服务商官方授权文档为准)。

GitHub

Scope 说明
repo 私有仓库的完整访问权限
read:user 读取用户公开资料
user:email 读取用户邮箱地址
gist 创建与管理 Gist
workflow 更新 GitHub Actions 工作流

示例:

{ provider: 'github', scopes: ['repo', 'read:user'] }

Google

Scope 说明
email 查看邮箱地址(默认)
profile 查看基本资料(默认)
openid OpenID Connect(默认)
https://www.googleapis.com/auth/calendar Google Calendar 访问
https://www.googleapis.com/auth/drive Google Drive 访问
https://www.googleapis.com/auth/gmail.readonly 只读 Gmail 邮件

示例:

{ provider: 'google', scopes: ['https://www.googleapis.com/auth/calendar'] }
// Or use defaults (email, profile, openid):
{ provider: 'google' }

注意:Google 的三个默认 scope(emailprofileopenid)在省略 scopes 时自动附带,因此 { provider: 'google' } 即可发起标准 OIDC 登录。

Notion

Notion 只使用单一的 OAuth scope,实际可访问范围由用户在授权时勾选的具体页面决定,因此无需(也无法)预先细分权限,直接写出 provider 名即可。

Linear

Scope 说明
read 读取 Linear 数据
write 写入 Linear 数据
issues:create 创建 Issue

在仓库里可以找到与上述 provider 一一对应的客户端接入代码,例如 GitHub/Google/Notion/Linear/Twitter/Todoist 等各自的 _auth.py/_oauth.py/_config.py(位于 backend/blocks 下对应服务商目录,如 github/_auth.pygoogle/_auth.pylinear/_oauth.pynotion/_auth.py),它们是同一套 OAuth 接入规范在"AutoGPT 作为客户端"一侧的实际落地,可作为理解 scope 与服务能力的参照。

六、PKCE 实现(授权码交换必需)

PKCE(Proof Key for Code Exchange)被官方明确为所有授权请求的强制要求。原理:你先本地生成一个随机 code_verifier,把它做 SHA-256 + Base64URL 得到 code_challenge 放进授权 URL;换 Token 时再提交原始 code_verifier,服务端比对两者是否匹配。这样即使授权码在传输中被截获,没有 verifier 的第三方也无法完成兑换。

JavaScript 示例

async function generatePkce() {
  // Generate a random code verifier
  const array = new Uint8Array(32);
  crypto.getRandomValues(array);
  const verifier = Array.from(array, b => b.toString(16).padStart(2, '0')).join('');

  // Create SHA-256 hash and base64url encode it
  const hash = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(verifier));
  const challenge = btoa(String.fromCharCode(...new Uint8Array(hash)))
    .replace(/\+/g, '-')
    .replace(/\//g, '_')
    .replace(/=+$/, '');

  return { verifier, challenge };
}

// Usage:
const pkce = await generatePkce();
// Store pkce.verifier securely (e.g., in session storage)
// Use pkce.challenge in the authorization URL

Python 示例

import hashlib
import base64
import secrets

def generate_pkce():
    # Generate a random code verifier
    verifier = secrets.token_urlsafe(32)

    # Create SHA-256 hash and base64url encode it
    digest = hashlib.sha256(verifier.encode()).digest()
    challenge = base64.urlsafe_b64encode(digest).decode().rstrip('=')

    return verifier, challenge

# Usage:
verifier, challenge = generate_pkce()
# Store verifier securely in session
# Use challenge in the authorization URL

实现要点:

  • verifier 必须使用密码学安全随机源(浏览器 crypto.getRandomValues、Python secrets),不要用时间戳、UUID 或可预测种子;
  • challenge 是 verifier 的 SHA-256 摘要经 Base64URL 编码、去掉尾部 =
  • verifier 需存到会话中,待 Step 3 换 Token 时取用;challenge 随授权请求一起发出;
  • 后端对二者的绑定校验(即 PKCE 校验)在换取 Token 阶段强制执行,从而保证 Step 1 中 code_challenge 的必填与 Step 3 中 code_verifier 的存在是配套成对的安全约束。

七、Token 生命周期、检查与吊销

令牌有效期

官方文档给出的默认生命周期,与 数据层源码常量 完全一致(AUTHORIZATION_CODE_TTL/ACCESS_TOKEN_TTL/REFRESH_TOKEN_TTL):

Token 类型 有效时长
Access Token 1 小时
Refresh Token 30 天
Authorization Code 10 分钟

同时源码还揭示了令牌的命名与格式约定(data/auth/oauth.py#L49-L50):access token 统一以 agpt_xt_ 开头、refresh token 以 agpt_rt_ 开头。你的应用可据此在日志与排障中快速区分令牌类型,也便于实现"会话中途换新"。

Token Introspection(检查有效性)

拿不准某个 token 是否仍有效时,可调用 introspection 端点:

POST /api/oauth/introspect
Content-Type: application/json

{
  "token": "agpt_xt_...",
  "token_type_hint": "access_token",
  "client_id": "{YOUR_CLIENT_ID}",
  "client_secret": "{YOUR_CLIENT_SECRET}"
}

响应:

{
  "active": true,
  "scopes": ["EXECUTE_GRAPH", "READ_GRAPH"],
  "client_id": "agpt_client_...",
  "user_id": "user-uuid",
  "exp": 1705320000,
  "token_type": "access_token"
}

响应里的 active 字段用于判断 token 是否有效,exp 为过期时间戳,user_id 可用来反查令牌归属用户。源码侧对应 introspect_token 等数据层函数(data/auth/oauth.py 顶部 import 列表可见 introspect_token/revoke_access_token/revoke_refresh_token/refresh_tokens 等完整能力,统一供 /api/oauth/* 端点调用)。

Token Revocation(吊销)

当用户在应用内退出登录、或解除对你应用的授权时,应当主动吊销令牌:

POST /api/oauth/revoke
Content-Type: application/json

{
  "token": "agpt_xt_...",
  "token_type_hint": "access_token",
  "client_id": "{YOUR_CLIENT_ID}",
  "client_secret": "{YOUR_CLIENT_SECRET}"
}

吊销在服务端落地后,对应 token 的 SHA-256 摘要会被标记失效(见数据层 revoke_access_token / revoke_refresh_token),从而真正实现"用户撤销授权即生效"的承诺,这也是选择 OAuth 而非静态 API Key 的价值所在。

八、服务端如何校验 scope:一次从外部 API 到权限枚举的透视

很多接入方会困惑"scope 到底有没有被真正执行"。可以确认的是,AutoGPT Platform 的权限模型把 scope 与 APIKeyPermission 枚举(EXECUTE_GRAPHREAD_GRAPHIDENTITYREAD_INTEGRATIONSMANAGE_INTEGRATIONS 等,该枚举定义于 schema.prisma 并通过 Prisma 生成)绑定,OAuth 应用注册时声明它允许的 scopes(OAuthApplicationInfo.scopes)。完整链路为:

  1. 用户授权时,后端校验应用是否有权请求这些 scope——越权会以错误终止授权(授权端点在 oauth.py 内完成 validate_scopes 等校验);
  2. 发放的 access token 上固化了最终 scope 集合;
  3. 每次外部 API 调用,外部 API 中间件 解析 Bearer token 后,各端点用 require_permission(...)(见 api/external/v1/routes.py)核对调用者令牌是否包含所需权限,不足即返回 403。

也就是说,你在 Step 1 请求的 scope 不是"装饰性参数",而是会被端到端执行的授权边界。对端到端流程感兴趣的话,仓库 oauth_test.py 覆盖了从授权、换 Token 到权限校验的完整用例(其中大量断言针对 EXECUTE_GRAPH/READ_GRAPH scope 的申请、校验与拒绝路径),是理解行为契约的最佳参考。

九、安全最佳实践

官方文档列出的七条安全基线,逐条落实到实现上:

  1. 机密凭证绝不落地前端:Client Secret 只应存在于你的服务端环境变量或密钥管理服务中,禁止写入客户端代码或版本控制;
  2. 始终使用 PKCE:这是所有授权请求的强制项,后端代码在模型层就要求 code_challenge 必填;
  3. 校验 state:回调时比对 state,防止 CSRF 与登录劫持;
  4. 全链路 HTTPS:所有生产环境的 Redirect URI 必须是 HTTPS;
  5. 最小权限申请:只请求应用真正需要的 scope,降低令牌泄漏时的爆炸半径;
  6. 自动续期:监听 access token 1 小时过期,用 refresh token 静默续期,避免用户操作中断;
  7. 登出即吊销:用户在应用内解绑/退出时调用 revoke 端点清理令牌。

还可以补充两点来自源码实现的安全事实:

  • 平台侧对 Client Secret 采用 Scrypt 加盐哈希存储、对 access/refresh token 采用 SHA-256 摘要存储(data/auth/oauth.py#L7-L10),数据库即使泄露也无法直接还原明文令牌;
  • 授权码为单次使用且 10 分钟过期,换取 Token 后立即作废,配合 PKCE 共同抵御授权码截获攻击。

十、错误处理

常见 OAuth 错误

错误 含义 解决方案
invalid_client Client ID 不存在或已被停用 核对 Client ID 是否正确、应用是否仍为启用状态
invalid_redirect_uri 回调地址未注册 联系平台管理员把该 URI 加入白名单
invalid_scope 请求了应用未被允许的 scope 检查应用允许的 scopes 集合
invalid_grant 授权码已过期或已被消费 授权码只能使用一次,失效后需重新走授权流程
access_denied 用户在同意页拒绝了授权 在前端 UI 中优雅降级处理

源码侧相应定义了 InvalidClientErrorInvalidGrantErrorInvalidTokenError 等异常族(data/auth/oauth.py#L58-L84),服务端把内部原因封装后映射为上文错误码返回给应用,避免泄露内部细节。

HTTP 状态码约定

状态码 含义
200 成功
400 请求参数错误(如授权码/参数非法)
401 未授权(token 非法或过期)
403 权限不足(scope 不够)
404 资源不存在

十一、延伸阅读与仓库参考

  • 通用 API 端点与 Available Scopes 的完整清单,见 API Guide
  • OAuth Provider 端点的服务端实现(authorize/token/introspect/revoke 及应用信息查询):api/features/oauth.py
  • 授权码、Token、应用注册的数据层(TTL、哈希、异常定义):data/auth/oauth.py
  • 端到端行为契约测试:oauth_test.py,以及增量式(追加 scope 的二次授权)测试 incremental_oauth_test.py
  • OAuth 应用相关的数据库表结构定义可追溯至 schema.prismaOAuthApplicationOAuthAuthorizationCodeOAuthAccessTokenOAuthRefreshToken 等模型,以及 migrations 目录 下的 20251212165920_add_oauth_provider_support 等迁移脚本;
  • 集成配置向导的前端实现:auth/integrations/setup-wizard/page.tsx/auth/integrations/setup-wizard/page.tsx)。

在实际对接过程中,服务端暴露的 OpenAPI/Swagger 文档(部署实例的 /external-api/docs 端点)可以用作端点级接口的实时速查手册;生产环境接入后,建议把令牌的获取、续期、吊销封装成独立服务端模块,配合监控告警跟踪 401/403 频率,以及时发现 scope 配置或密钥轮换问题。

登录后查看全文
热门项目推荐
相关项目推荐