【编者按】这篇文章介绍了 OAuth 的实践中的问题,如:OAuth 标准过于庞大和复杂、每个人的 OAuth 都有细微的不同、许多 API 在 OAuth 中添加了非标准的扩展、 调试 OAuth 很难、在 API 之上构建应用需要繁琐的审批、OAuth 存在安全性问题等。作者构建的一个开源服务 Nango,它旨在简化 OAuth 的流程和提高安全性,适用于多种 API,来解决这些问题。
链接:https://www.nango.dev/blog/why-is-oauth-still-hard
作者 | Robin Guldener译者 | 明明如月
责编 | 夏萌
出品 | CSDN(ID:CSDNnews)
我们为 50 个最受欢迎的 API 实现了 OAuth。结果:一言难尽。
图源:nango.dev
OAuth 是一个标准协议,它支持 OAuth 2.0 的客户端库已经存在,几乎适用于你能想象到的所有编程语言。你可能因此会得出结论,有了客户端库,你应该能在大约 10 分钟或至少一小时内实现任何 API 的 OAuth。然而,理想很丰满,现实很骨感。很难想象一个人能够在 10 分钟或一小时内实现任何 API 的 OAuth。
实践中的 OAuth
我们针对 50 种最受欢迎的 API 使用了OAuth,如 google (GmAIl、日历、表格等),HubSpot,Shopify,Salesforce,Stripe,Jira,Slack,Microsoft (Azure, Outlook, OneDrive),LinkedIn,Facebook 和其他使用OAuth 的 APIs。
我们的结论:现在 OAuth 的体验和 2008 年的 JAVA 的浏览器 API 差不多。虽然大家普遍认同事情应该如何做,但实际上每个 API 都有自己对标准的解读,实现上的差异和特殊性,以及非标准行为和扩展。结果是:每个细节都有可能出现问题和错误。
到底问题出现在哪里,让我们深入研究一下!
问题1:OAuth 标准过于庞大和复杂
"这个 API 也使用 OAuth 2.0,我们几周前已经做过了。我明天就能搞定。"——实习生的最后一句话
OAuth 是一个庞大的标准。它由官方网站上的 17 个 RFC(定义标准的文档)共同构成。它们涵盖了从 OAuth 框架和 Bearer 令牌到威胁模型和私钥 JWT 的所有内容。
你可能会问:“所有这些 RFC 都和一个简单的第三方访问令牌授权 API 有关吗?”你说得对。让我们只关注那些可能与典型的 API 第三方访问用例相关的东西:
如果你觉得这还是太复杂了,需要学习很多东西,我们倾向于同意你的看法。大多数构建公共 API 的团队似乎也同意这一点。他们没有遵循完整的 OAuth 2.0 标准,而只是根据他们的 API 用例选择性地实现了一些 OAuth 功能。这导致了文档中很长的页面,概述了 OAuth 对于这个特定 API 是如何工作的。但我们很难责怪他们;他们只是想要提供一个好的开发者体验(developer experience,DX),让他们的 API 更容易使用和理解,而不是遵循复杂的标准。他们可能认为 OAuth 2.0 标准太复杂或不适合他们的场景,所以他们只选择了一些他们认为有用的功能。虽然这可能是出于好心,但也可能导致混乱和不一致。
Salesforce 的authorization_code OAuth流程。这个简单的10步过程的清晰视图有什么不好呢?
问题是,每个人对 OAuth 的理解都有不同的想法,所以你最终得到了很多不同的(子)实现。
问题 2:每个人的 OAuth 都有细微的不同
每个 API 都实现了不同的 OAuth 子集,这迫使你仔细阅读他们冗长的 OAuth 文档:
1、他们在授权调用中需要哪些参数?
2、他们希望在令牌请求调用中看到什么?
3、我应该把我的用户重定向到哪里去授权?
4、但至少我可以选择我的回调 URL,对吧?
我们可以继续说很久,但我们想你现在应该明白了。
OAuth 太复杂了;让我们做一个更简单的 OAuth 版本,它有我们需要的一切!©XKCD
问题 3:许多 API 在 OAuth 中添加了非标准的扩展
尽管 OAuth 标准很全面,但许多 API 仍然发现它有一些功能缺失。我们遇到的一个常见问题是,除了access_token 之外,你还需要一些数据才能与 API 交互。这些额外的数据如果可以在 OAuth 流程中与access_token一起返回给你,会更方便。
但这确实意味着更多的非标准行为,你需要为每个 API 特别实现。
下面是我们看到的一些非标准扩展的列表:
为了简洁和简单起见,我们跳过了我们遇到的许多不太标准的 OAuth 流程。
问题 4:“invalid_request” —— 调试 OAuth 很难
调试分布式系统本就不易,如果服务返回的是广泛的、通用的错误消息,就更加困难了。
OAuth2 有标准化的错误消息,但它们在告诉你发生了什么方面,和标题中的例子一样有用(顺便说一下,这是 OAuth 标准推荐的错误消息之一)。
你可能会认为 OAuth 是一个标准,每个 API 都有文档,所以不需要调试。很多。我无法告诉你文档有多少次是错的。或者缺少细节。或者没有更新最新的变化。或者你第一次看它们时错过了什么。我们实现的大约 80% 的 OAuth 流程在第一次实现时都有一些问题,需要调试。
Randall 似乎能看穿我调试 OAuth 流程的心情?©XKCD
有些流程也会因为看似随机的原因而中断:例如,LinkedIn OAuth 会在你传入 PKCE(Proof Key for Code Exchange)参数时中断。你得到的错误是什么?“client error - invalid OAuth request。”这是……有说服力的吗?我们花了一个小时才明白传入(可选的,通常被忽略的)PKCE 参数是什么导致了流程中断。另一个常见的错误是发送与你预先注册的应用不匹配的 scope。(预先注册 scope?是的,现在很多 API 都要求这样做。)这通常会导致一个关于 scope 有问题的通用错误消息。真是令人沮丧。
问题 5:在 API 之上构建应用需要繁琐的审批
事实是,如果你要利用第三方的 API 来为其他平台或服务构建应用,你可能处于弱势的位置。你的客户要求集成,是因为他们已经在使用其他系统了。现在你需要让他们满意。
客观地说,许多 API 都很灵活,提供了方便的自助注册流程,让开发者可以注册他们的应用并开始使用 OAuth。但是一些最受欢迎的 API 需要在你的应用变成公开并且可以被他们的任何用户使用之前进行审核。再次公平地说,大多数审核过程都是合理的,可以在几天内完成。它们可能对于最终用户的安全和质量有净增益。
但但是一些出了名的例子可能需要花费几个月才能完成,有些甚至要求你进入收入分成协议:
问题 6:OAuth 存在安全性问题
随着 OAuth 的安全漏洞被发现,以及网络技术的进步,OAuth 标准也不断更新和完善。如果你想要实现当前的安全最佳实践,OAuth 工作组有一个详细的指南供你参考。如果你正在与一个仍然使用 OAuth 1.0a 的 API 合作,你就会意识到向后兼容性是一个持续的挑战。
幸运的是,每一次迭代,安全性都在变得更好,但这通常是以开发者更多工作为代价的。即将到来的 OAuth 2.1 标准将使一些当前的最佳实践成为强制性的,并包括强制性的 PKCE(今天只有少数 API 需要这个)和刷新令牌的额外限制。
至少 OAuth 已经实现了一个双因素认证模型。©XKCD
最大的变化可能是由过期的访问令牌和刷新令牌的引入引发的。理论上,这个过程看起来很简单:每当一个访问令牌过期时,用刷新令牌刷新它,并存储新的访问令牌和刷新令牌。实际上,当我们实现这个功能时,我们必须考虑:
最后:一些我们还没有谈到的事情
不幸的是,我们只是触及了你的 OAuth 实现的表面问题。现在你的 OAuth 流程运行起来了,你得到了访问令牌,是时候考虑以下问题了:
有更好的方法吗?
如果你读到这里,你可能会想,“一定有更好的方法!”
我们认为有,这就是为什么我们正在构建 Nango:一个开源、自包含的服务,它提供了预先构建好的 OAuth 流程、安全的令牌存储和自动令牌刷新适用于 90 多个 OAuth API。
如果你试一试,我们很乐意听到你的反馈。如果你想和我们分享你最糟糕的 OAuth 恐怖故事,我们也很乐意在我们的 Slack 社区中听到。
OAuth 的实践过程中,除了本文提到的问题外,还有哪些问题?