Composio × Notion 集成实战:认证模型、连接过期排查与 Webhook 触发器配置
Notion 是 Composio 生态中最典型的"页面级授权 + OAuth2"型集成之一:它不用 OAuth scopes 控制权限,而是通过授予集成对特定页面与数据库的访问权来工作,这带来了一系列与 GitHub、Slack 等截然不同的认证与连接管理问题。本篇以 Composio 仓库中的 Notion FAQ 文档 为主线,结合仓库内的认证配置示例与触发器源码,系统梳理 Notion 集成身份模型的原理、自定义集成的接入方式、连接过期根因,以及 Webhook 入口端点与数据库触发器的完整配置流程。读完你不仅能独立完成 Composio + Notion 的认证与触发器搭建,还能准确排查"操作归属显示异常、连接莫名过期、触发器不响应更新"这三类高频问题。
Notion 的集成身份模型:为什么操作显示 "Composio" 而不是用户名称
Notion 将操作归属于集成(integration)本身,而非发起操作的个人用户。因此,当你通过 Composio 托管凭据执行 Notion 工具时,Notion 侧展示的名称与 Logo 均来自集成配置,而不是当前登录用户,这并非数据错误。
- 若使用 Composio 托管(Composio-managed)的 Notion 应用,操作显示的就是 Composio 集成自身的名称与标识;
- 若希望展示自定义名称或 Logo,正确做法是在 Notion 开发者平台创建自己的集成,并将该集成作为自定义认证接入 Composio(详见下文"通过 Auth Config 接入自定义 Notion 集成"一节)。
从源码结构看,这一行为完全由 Notion 平台的集成模型决定,与 Composio 的执行层无关——Composio 仅负责代理认证与工具调用,动作归属权在 Notion 侧。理解这一点,是排查"页面操作记录中看不到真实用户"类问题的基础。
页面级授权:没有 OAuth Scopes 的访问控制模型
与大多数 OAuth2 服务不同,Notion 不使用 OAuth scopes 控制权限。访问控制通过"授予集成对特定页面与数据库的访问权"实现:
- OAuth 应用(public,即公开集成):授权时由用户主动选择要共享给集成的页面,选择结果即权限范围;
- 内部集成(API key 方式):页面访问权限在集成设置页中管理,用户通过"连接"面板逐页添加或移除。
这对 Composio 的直接含义是:创建 Notion 的 auth config 时,不需要传任何 scopes 参数。在 programmatic-auth-configs.mdx 中,Notion 的 auth config 仅需 client_id、client_secret 与 oauth_redirect_uri,全程未出现 scope 字段;如需按集成类型动态校验必填字段,可调用 composio.toolkits.get_auth_config_creation_fields(toolkit="notion", auth_scheme="OAUTH2") 获取。
通过 Auth Config 接入自定义 Notion 集成
生产环境中,Composio 官方强烈建议使用自己的 Notion 应用,使终端用户的 Token 与你的产品隔离。接入方式即创建自定义 auth config:
# 摘自 python/examples/auth_configs.py
from composio import Composio
composio = Composio()
# 使用自定义 Notion OAuth 应用
auth_config = composio.auth_configs.create(
toolkit="notion",
options={
"name": "Notion Auth",
"type": "use_custom_auth",
"auth_scheme": "OAUTH2",
"credentials": {
"client_id": "1234567890",
"client_secret": "1234567890",
"oauth_redirect_uri": "https://backend.composio.dev/api/v1/auth-apps/add",
},
},
)
print(auth_config)
关键参数说明:
type: "use_custom_auth":声明使用你自带的 OAuth 凭据,而非use_composio_managed_auth(托管模式最快上手,但归属与速率配额受 Composio 集成约束);auth_scheme: "OAUTH2":Notion 采用 OAuth2 授权码流程;oauth_redirect_uri:在 Notion 开发者平台注册应用时填写的回调地址,必须指向 Composio 的回调端点https://backend.composio.dev/api/v1/auth-apps/add。根据 programmatic-auth-configs.mdx 的说明,省略该字段时使用 Composio 默认回调,仅在需要将回调路由到自有域名时才显式指定;- 创建成功后返回的
ac_xxx形式的 auth config ID,可用于后续会话绑定:composio.sessions.create(user_id="user_123", auth_configs={"notion": auth_config.id})。
此外,auth_configs.py 还展示了完整的生命周期管理:通过 composio.toolkits.get_auth_config_creation_fields() 查询必填字段、auth_configs.update() 更新凭据、以及 enable() / disable() / delete() 启停与删除。若要为会话固定 Notion 工具版本,可在 Composio(toolkit_versions={"notion": "latest"}) 中指定(见 custom-auth-params.mdx)。
管理页面访问权限:连接与页面选择
已接入的集成需要按需调整可访问的页面范围,操作路径完全位于 Notion 侧:
- 打开 Notion,进入 Settings & Members(设置与成员) → Connections(连接);
- 选择集成(Composio 托管应用或你的自定义集成);
- 点击 "Select pages"(选择页面) 或 "Manage access"(管理访问权限);
- 按需添加或移除页面与数据库。
值得注意的是,页面访问权限是动态的:新增页面不会自动对已连接集成开放,必须手动在连接面板中授权;同理,移除访问权即可即刻收回。这一模型决定了"用户看似已连接但工具调用 403"多半是页面授权缺失,而非 Token 失效。
Notion 连接过期的两大根因与最佳实践
Notion 连接失效通常由两类原因触发:
1. 用户在 Notion 侧主动断开集成
Notion 文档明确指出,通过 OAuth 安装的公开连接会出现在 Settings → Connections 中,且可从工作区直接断开。一旦用户移除了 Composio 托管应用或自定义 Notion 应用,该连接对应的 Token 集应视为已撤销,产品侧需要引导用户重新连接。这类断开在 Notion 界面中不会向 Composio 发送显式事件,只能通过后续 API 调用失败间接发现。
2. 同一用户通过同一 Notion 应用重复连接,触发 Token 轮换
当 Notion 用户连接到一个 Notion 应用时,Notion 会为本次连接签发一对新的 access_token 与 refresh_token。若同一用户对同一应用再次连接(无论应用由 Composio 托管还是自定义),Notion 可能签发新 Token 对并使旧的 refresh_token 失效。此时:
- 旧
access_token可能在一段时间内仍可用; - 一旦旧 Token 过期,旧连接无法再刷新,应视为过期。
规避最佳实践:
- 对给定的 Notion 应用,每个真实用户只维护一条活跃连接;
- 在产品中复用已有连接,避免反复要求用户重连;
- 生产环境优先使用自己的 Notion 应用,使用户 Token 与你的产品隔离,降低跨应用 Token 轮换带来的干扰。
配置 Notion Webhook 入口端点(Webhook Ingress)
Notion 触发器(trigger)依赖 Webhook 将事件推送到 Composio。入口端点的配置方式取决于凭据来源:
- Composio 托管凭据:入口端点已自动预置,只需直接创建触发器即可;
- 自带 Notion OAuth 应用:验证流程与 Slack 相反——Notion 会向入口端点发送一个验证 Token,你需要将该 Token 回填到 Notion 侧完成确认。
完整步骤如下(摘自 notion.md):
第 1 步:创建端点
curl -X POST "https://backend.composio.dev/api/v3.1/webhook_endpoints" \
-H "x-api-key: <YOUR_COMPOSIO_API_KEY>" \
-H "Content-Type: application/json" \
-d '{"toolkit_slug": "notion", "client_id": "<YOUR_NOTION_OAUTH_CLIENT_ID>"}'
保存响应中的 id 与 webhook_url 两个字段。根据 custom-oauth-webhooks.mdx 的说明,该调用按 (toolkit_slug, client_id) 在项目内幂等——重复调用同一组合会返回既有端点,而不会轮换 URL 或清除签名秘密。
第 2 步:把 webhook_url 填入 Notion
在 Notion 集成的 Webhook 设置中粘贴该 URL。对于 Notion 这类会发起验证挑战的提供方,Composio 会自动响应,无需在己方实现握手代码。
第 3 步:从 Composio 读取验证 Token
curl "https://backend.composio.dev/api/v3.1/webhook_endpoints/<ENDPOINT_ID>" \
-H "x-api-key: <YOUR_COMPOSIO_API_KEY>"
Token 位于响应体的 data.webhook_signing_secret 字段。
第 4 步:回填验证字段
将 Token 粘贴回 Notion 的 verify 字段,完成设置,随后即可继续创建触发器。签名秘密是项目级(project-scoped)的,仅在本项目内生效;端点验证完成后,重复的验证握手会被拒绝,防止签名秘密被伪造挑战静默替换(详见 custom-oauth-webhooks.mdx 的安全说明)。在 SDK 侧,triggers.py 中的校验逻辑要求按 webhook-signature 请求头(格式 v1,base64EncodedSignature)执行 HMAC-SHA256 验签,验证失败即抛出 WebhookSignatureVerificationError,因此在自建事件接收端时必须妥善处理签名校验。
Notion 数据库触发器:新增触发、更新不触发
在手动测试中观察到:向被监听数据库新增页面时触发器正常触发,但页面内容更新不会触发。这是 Notion 平台对 Webhook 事件类型的实际限制,并非 Composio 配置问题。
验证方式:向目标数据库新增一个页面,观察触发器是否产生事件;若需对更新事件建模,应考虑轮询比对或结合 Notion 页面元数据(如 last_edited_time)自行实现增量检测。由于 Notion 侧的事件语义如此,依赖"更新即触发"的自动化流程需要额外的工程兜底。
小结
围绕 Composio 接入 Notion,核心结论可归纳为四点:
- 身份归属是集成级的:操作显示名称来自集成配置,自定义品牌需自建 Notion 应用;
- 权限是页面级的:没有 OAuth scopes,通过"连接 + 选页"管理访问范围,auth config 创建时无需传 scopes;
- 连接过期由"用户主动断开"或"重复连接触发 Token 轮换"引起,最佳实践是每个用户每个应用只保留一条活跃连接并复用;
- Webhook 入口需按"创建端点 → 填 URL → 取签名秘密 → 回填 Notion"四步走,且数据库触发器仅对新增页面生效。
对于更深层的接入细节,可继续阅读仓库内的 programmatic-auth-configs.mdx(认证配置全参数)、custom-oauth-webhooks.mdx(通用 Webhook 入口流程)、auth_configs.py(可运行的认证生命周期示例)以及 triggers.py(触发器与签名校验实现)。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0634
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
jforgamejforgame是一个一站式游戏服务器开发框架。包含游戏服务器开发所需要的各种组件,比如网关,socket服务端与客户端,自定义高效消息编解码,游戏热更新,游戏通用工具等等。包含游戏服,跨服,匹配服,后台管理系统等实现,同时提供大量业务案例以供学习。亦可用于其他socket应用,例如及时聊天等。Java01
fizz-gateway-nodeAn Aggregation API Gateway in Java . FizzGate 是一个基于 Java开发的微服务聚合网关,是拥有自主知识产权的应用网关国产化替代方案,能够实现热服务编排聚合、自动授权选择、线上服务脚本编码、在线测试、高性能路由、API审核管理、回调管理等目的,拥有强大的自定义插件系统可以自行扩展,并且提供友好的图形化配置界面,能够快速帮助企业进行API服务治理、减少中间层胶水代码以及降低编码投入、提高 API 服务的稳定性和安全性。Java00
certd开源SSL证书管理工具;全自动证书申请、更新、续期;通配符证书,泛域名证书申请;证书自动化部署到阿里云、腾讯云、主机、群晖、宝塔;https证书,pfx证书,der证书,TLS证书,nginx证书自动续签自动部署JavaScript00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00