Composio Salesforce 工具包实战指南:OAuth 配置、域名修复与常见错误排查
本文围绕 Composio 开源仓库中的 Salesforce 集成文档,系统梳理 Salesforce 工具包的自定义 OAuth 凭据配置、连接字段(My Domain 子域与 Instance 端点)的填写规范、URL_NOT_RESET / OAUTH_APPROVAL_ERROR_GENERIC 等典型错误的原因与修复路径、刷新令牌配额限制,以及关系型数据查询(SOQL 子查询)与工具选型建议,帮助你快速定位并解决 Salesforce 集成中的真实故障。
一、连接前的必填字段:子域与 Instance 端点
在 Composio 中发起 Salesforce 连接时,有两个关键字段需要确认:
- My Domain Subdomain(My Domain 子域):例如
your-company.my; - Instance endpoint(实例端点):例如
/services/data/v61.0。
这两项属于 Salesforce 接受的"附加连接发起字段"。如果你通过 SDK/API 直接发起连接,应将它们通过 .initiate() 传入,而不是依赖托管连接 UI 去收集;详细字段说明可参考 docs/content/toolkits/faq/salesforce.md 与 docs/kb/source/toolkits/salesforce/public.md。
子域取值格式
默认情况下 Salesforce 子域取值为 login,适用于大多数流程。但当组织有特定 My Domain 或使用 Developer Edition / Lightning 环境时,需要按下表格式传入登录/API 域前缀(注意是 API 域前缀,而非完整浏览器 URL):
| 场景 | 浏览器 URL 示例 | 应传入的子域 |
|---|---|---|
| 默认情况 | — | login |
| 标准 My Domain | https://your-company.my.salesforce.com/... |
your-company.my |
| Developer Edition / Lightning | https://<org>.develop.lightning.force.com/... |
<org>.develop.my(对应 OAuth 主机通常为 https://<org>.develop.my.salesforce.com/...) |
值得注意的边界情况:如果用户只输入了 <org>,Composio 可能生成 <org>.salesforce.com,这会在 OAuth 之前就因浏览器 DNS 解析失败而报错(如 DNS_PROBE_FINISHED_NXDOMAIN)。因此务必使用 My Domain 或 API 域前缀,而不是不完整的组织标签。相关原始文档位于 docs/kb/source/toolkits/salesforce/public.md(Salesforce subdomain defaults to login 一节)。
通过工具包 API 检查预期字段
你可以按 slug 拉取工具包定义来确认实际期望的字段列表:
GET /api/v3.1/toolkits/salesforce
连接成功后,再次拉取 connected account,即可看到连接后回填的相同字段。Composio 的 Salesforce 工具包 slug 在 ts/packages/cli/src/generated/toolkit-slugs.ts 中注册(salesforce、salesforce_service_cloud),可据此确认工具包名称拼写。
二、自定义 OAuth 凭据:托管认证与直接发起两条路径
Composio 的 Salesforce 工具包支持 OAuth2 与 server-to-server OAuth2,并且支持使用客户自有的凭据(customer-owned credentials)。做法是:按 Salesforce 官方的 OAuth 指引在 Salesforce 侧配置 Connected App,然后把该 App 的凭据填入 Composio 的自定义 Auth Config,从而获得对 scopes、品牌标识以及服务商侧策略的控制权。
路径 A:托管认证(Hosted Auth)
Salesforce 字段收集界面属于 Hosted Authentication / 连接链接流程的一部分。当你希望 Composio 代为收集必填字段(子域、实例端点)时,使用托管认证即可,用户会在连接 UI 中填写这些字段。
路径 B:直接调用 .initiate()
如果应用本身已经知道 Salesforce 实例与子域值,可以跳过字段收集界面,直接调用 .initiate() 并传入必填字段。相关方法语义如下:
.initiate():发起新连接并生成认证 URL;.refresh():为已发起的连接重新生成认证 URL;.link():开启一条全新连接;allow_multiple=True:当同一user_id确实需要多条连接时传入。
回调地址的区分
自定义 Salesforce OAuth 时,授权重定向 URI 应使用 Composio auth-config 流程中展示的 provider 回调端点(即 Composio 工具包 auth callback 地址)。它与连接发起时传入的 callback_url / callbackUrl(认证完成后的客户侧跳转地址)是两个不同概念,不要混淆。
三、常见错误深度排查
3.1 URL_NOT_RESET:子域未配置、回落到 login
现象:连接报 URL_NOT_RESET。
原因:Salesforce 组织要求使用特定的 My Domain 值,但连接仍在使用通用的 login 默认值,或使用了不完整的子域。
处理步骤:
- 重新核对连接上的 Salesforce 域/子域值;
- 传入正确的 My Domain 子域(参考上文格式表);
- 如果问题出现在旧版固定的工具包版本上,请升级到最新工具包版本后重试。
默认 login 值对大多数 Salesforce 流程是没问题的,只有组织级失败才需要替换为具体子域。
3.2 OAUTH_APPROVAL_ERROR_GENERIC 与 app must be installed into org
现象:OAuth 被 Salesforce 拦截,用户看到 OAUTH_APPROVAL_ERROR_GENERIC,或者回调 URL 中携带:
error=invalid_client&error_description=app+must+be+installed+into+org
原因:Connected App 尚未被组织安装或批准。Salesforce 的 connected app 使用限制可能要求组织管理员先安装/批准该应用,组织用户才能完成认证。
处理步骤:
- 让 Salesforce 组织管理员进入 Setup(设置);
- 搜索 External Client App Settings 或 OAuth Connected App Usage(可参考 docs/kb/source/toolkits/salesforce/public.md 中关于 OAuth Connected App Usage 的描述,Actions 列会显示 Install 按钮);
- 找到对应应用并执行 Salesforce 展示的安装/批准操作;
- 管理员批准后,用户重试 OAuth 连接。
3.3 每个用户每 App 仅允许 5 个有效刷新令牌
现象:同一 Salesforce 用户第 6 次连接后,较早的 Composio connected account 开始出现令牌错误。
原因:Salesforce 限制每个用户在每个 connected app 上最多拥有 5 个有效刷新令牌。同一用户连接第 6 次时,Salesforce 可能吊销最旧的刷新令牌。
排查清单(除配额外,还应检查):
- 用户是否更改了密码;
- 用户是否在 Salesforce 中撤销了该应用;
- connected app 的刷新令牌策略是否被改为非
valid until revoked; - 是否存在使令牌失效的组织级会话策略。
3.4 连接后找不到自己创建的数据
在 Salesforce 中创建的记录可能不会立即出现在某个给定视图里。此时应使用搜索(Search)确认记录确实存在,再决定是否需要调整视图或查询条件。
四、关系型数据查询:用 SOQL 子查询遍历关系
当需要查询 Pricebooks、Opportunities 等关联对象时,应使用 SOQL 子查询遍历对象关系。官方 FAQ 给出的示例是从 Opportunity 出发,向下展开 OpportunityLineItems,并顺带取到关联的 PricebookEntry 与 Product2 名称:
SELECT Id, Name,
(SELECT Id, Quantity, UnitPrice, TotalPrice, PricebookEntry.Product2.Name FROM OpportunityLineItems)
FROM Opportunity
这个例子展示了 Product → Pricebook → Opportunity 这条关系链的查询方式:外层查询 Opportunity,内层子查询通过 OpportunityLineItems 关系名取得明细,并用点号导航 PricebookEntry.Product2.Name 跨对象取字段。
五、工具选型:当前工具、废弃工具与 Schema 发现
5.1 用 SALESFORCE_GET_ALL_FIELDS_FOR_OBJECT 做 Schema 发现
在构建针对某个 Salesforce 对象的查询或更新流程之前,可以使用 SALESFORCE_GET_ALL_FIELDS_FOR_OBJECT 检查该对象可用字段,这是面向对象构建查询前的 Schema 发现手段。
5.2 废弃工具与迁移对照
废弃工具在正式移除前仍可继续使用,使用时请留意工具描述中的 DEPRECATED: 标记。FAQ 与知识库均给出了明确的迁移对照(见 docs/kb/source/toolkits/salesforce/public.md):
| 废弃工具(旧) | 当前工具(新) |
|---|---|
SALESFORCE_RETRIEVE_LEAD_BY_ID |
SALESFORCE_GET_LEAD |
SALESFORCE_RETRIEVE_SPECIFIC_CONTACT_BY_ID |
SALESFORCE_GET_CONTACT_BY_ID |
SALESFORCE_RETRIEVE_OPPORTUNITIES_DATA |
SALESFORCE_LIST_OPPORTUNITIES |
5.3 先列表后按 ID 取详情
推荐模式:先用 SALESFORCE_LIST_CONTACTS 列出联系人并记录 ID 与名称,再调用 SALESFORCE_GET_CONTACT_BY_ID 传入目标联系人 ID 获取明细,避免一次性深查带来的不确定性问题。
六、进阶:用 Proxy Execute 实现 Frontdoor/UI Bridge 流程
对于 Salesforce Frontdoor / UI Bridge 类流程,不要通过 connected account API 读取访问令牌来手动构造请求。正确做法是使用 Proxy Execute 并绑定 Salesforce connected account:
- Composio 会在服务端把 OAuth 访问令牌注入被代理的 Salesforce 请求(例如调用
/services/oauth2/singleaccess); - Salesforce 返回 frontdoor URI;
- 应用将用户的浏览器重定向到该 frontdoor URI,从而安全地进入 Salesforce UI。
这样访问令牌全程不出服务器,避免了在客户端暴露敏感凭据。
七、参考资料
- 本文核心来源:docs/content/toolkits/faq/salesforce.md
- 支持知识库原文:docs/kb/source/toolkits/salesforce/public.md
- 面向用户的知识库文章:docs/kb/articles/toolkits-salesforce.md
- 工具包 slug 注册:ts/packages/cli/src/generated/toolkit-slugs.ts
- 更多工具包 FAQ:docs/content/toolkits/faq
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 StartedRust0631
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
video-shotcraftAI宣传片skill,使用 Remotion 制作电影级产品视频:提供106 张镜头配方卡和可复用的视频魔板。适用于 Claude Code 与 Codex以及所有其他智能体Markdown00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python09
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00