每个社交平台都有自己的 OAuth 实现,它们大致的形状相似,除此之外几乎没有共同点。这篇文章讲的是你要为此付出什么,以及哪些部分可以跳过。
各平台的差异在哪里
权限范围(Scopes)。 名称不同,粒度不同,要求也不同。申请的范围太宽,应用审核会被拒绝。申请的范围太窄,某个功能就会悄悄失效。
令牌有效期。 有些令牌能用很久。有些几周就过期。有些可以通过一个你必须单独了解的调用,换成有效期更长的令牌。
刷新行为。 有些平台会颁发刷新令牌,有些要求重新授权,有些每次都会轮换刷新令牌,所以保存旧的那一个会导致下一次刷新失败。
审核。 有几个平台在审核你的应用之前不会授予发布权限,审核可能涉及隐私政策、演示视频,还要等待。这是你无法掌控的时间,而且可能被拒绝。
账号模型。 个人主页、主页(page)、企业账号和频道,是权限各不相同的不同对象。拿到令牌,不等于知道你到底能发布到哪个账号。
真正容易出问题的环节:刷新
不是最初的授权流程。最初的流程就是一天的工作量,做完就结束了。
在生产环境中真正出问题的是刷新,而且它出问题的时候很安静:
- 令牌过期了,而刷新任务三天前就已经失败
- 没有任何明显的报错,因为在这之前一直没有尝试发布
- 一条排期的帖子发布失败
- 用户比你更早发现这件事
任何正经的实现都需要一个定时刷新任务、针对刷新失败的监控、一种把某个连接标记为”已断开”的方式,以及界面上的重新连接提示。这比 OAuth 流程本身的工作量还大,而且是各种工作量估算里最常被漏掉的部分。
如果你自己实现
从一开始就值得做的事情:
把令牌加密存储,而且永远不要把它们写进日志。它们是别人账号的凭证。
存储过期时间,提前刷新,而不是等失败了再刷新。
处理轮换。 如果某个平台会轮换刷新令牌,先写入新的令牌,再去使用它,而不是相反。
把”连接已断开”建模成一个真实的状态。 而不是一个被你捕获的异常,而是用户能看到、也能修复的一种状态。
预期会有重新授权。 权限变更和政策更新意味着,无论你怎么做,用户偶尔都需要重新连接。
避开大部分工作量
如果发布功能只是你产品的一个特性,而不是产品本身,那么另一种选择是:只做一个集成,把各平台的 OAuth 交给别人去处理。
有两种认证模型,选对很关键:
API key,用于操作你自己的账号。服务器到服务器,没有用户同意流程,是能跑通的最简单方案。
OAuth,用于代表你的用户执行操作。他们批准你的应用,你就会拿到一个绑定在他们所选工作区上的、有权限范围限制的令牌,而不是让他们把凭证直接粘贴进你的产品里。
如果你的产品是多用户的,从一开始就用 OAuth。让用户粘贴 API key,是一次你以后终究要做的迁移,而且它会教会用户一个你并不希望他们养成的习惯。
BulkPublish 的 OAuth 是如何运作的

- 授权端点:
https://app.bulkpublish.com/oauth/authorize - 令牌端点:
https://app.bulkpublish.com/api/oauth/token - 每个客户端都必须使用 PKCE(S256)
scope是必填项,没有隐式默认值- 授权码是一次性的,刷新令牌会轮换
- 令牌以
Bearer bpat_...的形式传递
权限范围是细粒度的:posts:read、posts:write、media:read、media:write、analytics:read、channels:read,或者 full。
有一条刻意设置的边界值得了解:OAuth 令牌能够触达帖子、排期、标签、媒体、分析数据、配额使用情况,以及只读的频道数据,仅此而已。账号管理相关的操作,也就是团队、组织、账单、购买额度、API key 和 OAuth 应用管理,对任何 OAuth 令牌(包括 full)都会返回 403。这些操作的存续时间会超过用户断开你的应用连接之后的状态,所以它们要求使用 API key。
这种边界值得尽早纳入设计考虑,而不是等到生产环境里冒出一个 403 才发现。
简而言之
OAuth 流程每个平台大约一天的工作量。令牌刷新则是永无止境的工作,而且它会悄无声息地失败,这正是它真正让人头疼的原因。如果发布功能只是你产品的一个特性而不是产品本身,用一个服务商的集成就能省掉十五个这样的工程。一旦涉及别人的账号,就用 OAuth,而不是让用户粘贴 API key。