白皮书内容摘要见下,英文好的同学可自行阅读原文:
摘要(Abstract)
OAuth 2.0 授权框架允许第三方应用程序获得对 HTTP 服务的有限访问权限。这种访问可以代表资源所有者进行——通过协调资源所有者与 HTTP 服务之间的授权交互;也可以由第三方应用程序以自身名义直接获取访问权限。
引言(Introduction)
在传统的客户端-服务器认证模型中,客户端通过使用资源所有者的凭据(如用户名和密码)向服务器进行身份验证,从而请求访问服务器上受限制的资源(即受保护资源)。
为了使第三方应用程序能够访问这些受限资源,资源所有者不得不将自己的凭据共享给第三方。这种做法会带来若干问题和局限性:
- 第三方应用程序必须存储资源所有者的凭据以供将来使用,通常是以明文形式保存密码。
- 服务器被迫支持基于密码的认证机制,尽管密码本身存在固有的安全弱点。
- 第三方应用程序获得对资源所有者受保护资源的过度宽泛的访问权限,资源所有者无法限制访问的持续时间,也无法将访问权限限定于资源的一个子集。
- 资源所有者无法单独撤销某个第三方的访问权限,除非更改密码——而这会同时撤销所有第三方的访问权限。
- 一旦任意一个第三方应用程序被攻破,就会导致终端用户的密码泄露,以及所有由该密码保护的数据被泄露。
OAuth 通过引入一个授权层,并将客户端(client)的角色与资源所有者(resource owner)的角色分离,来解决上述问题。
在 OAuth 中,客户端请求访问由资源所有者控制、并托管在资源服务器(resource server)上的资源,但它所使用的凭据与资源所有者本身的凭据完全不同。
客户端不再使用资源所有者的凭据去访问受保护资源,而是获取一个访问令牌(access token)——这是一个字符串,代表特定的访问范围(scope)、有效期(lifetime)以及其他访问属性。
该访问令牌由授权服务器(authorization server)在获得资源所有者许可后颁发给第三方客户端。客户端随后使用此访问令牌向资源服务器请求受保护的资源。
例如,一位终端用户(资源所有者)可以授权一个打印服务(客户端)访问她存储在照片分享服务(资源服务器)中的受保护照片,而无需将她的用户名和密码透露给打印服务。
相反,她直接向照片分享服务所信任的服务器(即授权服务器)进行身份验证,该授权服务器随后向打印服务颁发仅用于此次委托的凭证(即访问令牌)。
1.1 角色
OAuth 定义了四种角色:
资源所有者(resource owner)
能够授予受保护资源访问权限的实体。当资源所有者是个人时,也称为终端用户(end-user)。
资源服务器(resource server)
托管受保护资源的服务器,能够接收并响应使用访问令牌(access token)发起的受保护资源请求。
客户端(Client)
代表资源所有者发起受保护资源请求并在其授权下进行操作的应用程序。“客户端”这一术语并不暗示任何特定的实现特征(例如,该应用程序是在服务器、桌面设备还是其他设备上运行)。
授权服务器(authorization server)
在成功对资源所有者进行身份验证并获得其授权后,向客户端颁发访问令牌的服务器。
授权服务器与资源服务器之间的交互不在本规范的范围之内。授权服务器可以与资源服务器为同一台服务器,也可以作为独立的实体存在。单个授权服务器可以颁发被多个资源服务器接受的访问令牌。
1.2 协议流程
sequenceDiagram
participant 客户端(Client)
participant 资源所有者(Resource Owner)
participant 授权服务器(Authorization Server)
participant 资源服务器(Resource Server)
客户端(Client)->>资源所有者(Resource Owner): (A) 授权请求(Authorization Request)
资源所有者(Resource Owner)-->>客户端(Client): (B) 授权许可(Authorization Grant)
客户端(Client)->>授权服务器(Authorization Server): (C) 授权许可(Authorization Grant)
授权服务器(Authorization Server)-->>客户端(Client): (D) 访问令牌(Access Token)
客户端(Client)->>资源服务器(Resource Server): (E) 访问令牌(Access Token)
资源服务器(Resource Server)-->>客户端(Client): (F) 受保护的资源(Protected Resource)
Note over 客户端(Client),资源服务器(Resource Server): 图1 OAuth 2.0 流程图
图1所示的 OAuth 2.0 流程图描述了四个角色之间的交互,包括以下步骤:
(A)客户端向资源所有者请求授权。
该授权请求可以直接发送给资源所有者(如图所示),但更推荐的方式是通过授权服务器作为中介间接发起。
(B)客户端收到一个授权许可(authorization grant),这是一种代表资源所有者授权的凭据,采用本规范中定义的四种授权类型之一或某种扩展授权类型来表达。
所使用的授权许可类型取决于客户端请求授权时采用的方法以及授权服务器所支持的类型。
(C)客户端通过向授权服务器进行身份认证,并出示该授权许可,来请求访问令牌(access token)。
(D)授权服务器对客户端进行身份认证,并验证授权许可;若验证通过,则颁发一个访问令牌。
(E)客户端向资源服务器请求受保护的资源,并通过出示访问令牌进行身份认证。
(F)资源服务器验证访问令牌,若有效,则处理该请求。
客户端从资源所有者处获取授权许可(如步骤(A)和(B)所示)的推荐方法是使用授权服务器作为中介,该流程在图4.1节的图3中展示。
1.3 授权许可(Authorization Grant)
授权许可是一种凭据,代表资源所有者对其受保护资源的访问授权,客户端使用该凭据来获取访问令牌(access token)。
本规范定义了四种授权许可类型——授权码(authorization code)、隐式模式(implicit)、资源所有者密码凭证(resource owner password credentials)和客户端凭证(client credentials)——同时还提供了一种可扩展机制,用于定义额外的授权类型。
1.3.1 授权码(Authorization Code)
授权码是通过在客户端与资源所有者之间引入授权服务器作为中介而获得的。
客户端并非直接向资源所有者请求授权,而是将资源所有者引导至授权服务器(通过其用户代理,如 [RFC2616] 中所定义),随后授权服务器再将资源所有者连同授权码一起重定向回客户端。
在将资源所有者连同授权码重定向回客户端之前,授权服务器会先对资源所有者进行身份认证并获取其授权。
由于资源所有者仅与授权服务器进行身份认证,因此其凭证永远不会透露给客户端。
授权码提供了若干重要的安全优势,例如:
- 能够对客户端进行身份认证;
- 访问令牌可直接传输给客户端,无需经过资源所有者的用户代理,从而避免了访问令牌被泄露给包括资源所有者在内的其他方的风险。
1.3.2 隐式许可(Implicit)
隐式许可是一种简化的授权码流程,专为使用脚本语言(如 JavaScript)在浏览器中实现的客户端而优化。
在隐式流程中,授权服务器不会向客户端颁发授权码,而是直接颁发访问令牌(作为资源所有者授权的结果)。
该许可类型被称为“隐式”,是因为没有颁发任何中间凭据(例如授权码),也就无需后续使用该凭据来换取访问令牌。
在隐式许可流程中颁发访问令牌时,授权服务器不会对客户端进行身份认证。在某些情况下,可通过用于将访问令牌传递给客户端的重定向 URI 来验证客户端身份。
然而,访问令牌可能会暴露给资源所有者,或暴露给其他能够访问资源所有者用户代理(如浏览器)的应用程序。
隐式许可提升了某些客户端(例如基于浏览器的应用)的响应速度和效率,因为它减少了获取访问令牌所需的往返交互次数。
然而,这种便利性必须与使用隐式许可所带来的安全风险进行权衡(如第 10.3 节和第 10.16 节所述),尤其是在授权码许可类型可用的情况下更应谨慎使用。
1.3.3 资源所有者密码凭证(Resource Owner Password Credentials)
资源所有者的密码凭证(即用户名和密码)可直接用作一种授权许可(authorization grant),以获取访问令牌(access token)。
这种凭证仅应在资源所有者与客户端之间存在高度信任关系时使用(例如,客户端是设备操作系统的一部分,或是一个具有高权限的应用程序),并且在其他授权许可类型不可用时(如授权码模式)才应考虑使用。
尽管该许可类型要求客户端直接获取资源所有者的凭证,但这些凭证仅用于单次请求,并会立即被交换为一个访问令牌。
通过将凭证交换为长期有效的访问令牌或刷新令牌(refresh token),该许可类型可以避免客户端为了未来使用而存储资源所有者的用户名和密码,从而提升安全性。
1.3.4 客户端凭证(Client Credentials)
当授权范围仅限于客户端自身控制的受保护资源,或已与授权服务器预先约定好的受保护资源时,客户端凭证(或其他形式的客户端身份认证方式)可用作一种授权许可。
通常在以下场景中使用客户端凭证作为授权许可:
- 客户端代表自身行事(即客户端本身就是资源所有者);
- 或客户端根据与授权服务器事先安排好的授权,请求访问受保护资源。
1.4 访问令牌(Access Token)
访问令牌是一种用于访问受保护资源的凭据。它是一个字符串,代表颁发给客户端的授权。该字符串对客户端而言通常是不透明的(opaque),即客户端无需理解其内部结构。
令牌体现了由资源所有者授予的、特定的访问范围(scope)和有效期(duration),并由资源服务器和授权服务器共同实施访问控制。
该令牌可以是:
- 一个标识符,用于在服务器端查找对应的授权信息;
- 或者以可验证的方式自包含授权信息(例如,令牌字符串中包含某些数据及其数字签名)。
此外,为了让客户端使用某个令牌,可能还需要提供超出本规范范围的其他身份认证凭据。
访问令牌提供了一层抽象,用资源服务器能够理解的单一令牌,替代了各种不同的授权机制(例如用户名和密码)。这种抽象具有以下优势:
- 允许颁发的访问令牌所具有的权限比获取它时所使用的授权许可更加受限;
- 使资源服务器无需理解多种多样的身份认证方法。
访问令牌可以根据资源服务器的安全需求,采用不同的格式、结构和使用方式(例如不同的加密特性)。
至于令牌的具体属性以及访问受保护资源所使用的方法,不在本规范的范围之内,而是由配套规范(如 [RFC6750])进行定义。
1.5 刷新令牌(Refresh Token)
刷新令牌是一种用于获取访问令牌(access token)的凭证。授权服务器向客户端颁发刷新令牌,当当前的访问令牌失效或过期时,客户端可使用该刷新令牌来获取新的访问令牌;此外,也可用它来获取具有相同或更窄权限范围的额外访问令牌(访问令牌的有效期可能比资源所有者授权的更短,所拥有的权限也可能更少)。是否颁发刷新令牌由授权服务器自行决定,属于可选项。如果授权服务器选择颁发刷新令牌,则在颁发访问令牌时一并返回(即图 1 中的步骤 (D))。
刷新令牌是一个字符串,代表资源所有者授予客户端的授权。该字符串对客户端而言通常是不透明的(opaque),即客户端无需理解其内部结构。此令牌本质上是一个标识符,用于检索相关的授权信息。与访问令牌不同,刷新令牌仅用于与授权服务器交互,绝不会发送给资源服务器。
sequenceDiagram
title 图2 OAuth 2.0 刷新令牌流程图
participant 客户端(Client)
participant 授权服务器(Authorization Server)
participant 资源服务器(Resource Server)
客户端(Client)->>授权服务器(Authorization Server): (A) 授权许可
授权服务器(Authorization Server)-->>客户端(Client): (B) 访问令牌 & 刷新令牌
客户端(Client)->>资源服务器(Resource Server): (C) 携带访问令牌请求资源
资源服务器(Resource Server)-->>客户端(Client): (D) 返回受保护资源
客户端(Client)->>资源服务器(Resource Server): (E) 使用相同访问令牌请求资源
资源服务器(Resource Server)-->>客户端(Client): (F) 返回令牌无效错误
客户端(Client)->>授权服务器(Authorization Server): (G) 使用刷新令牌请求新令牌
授权服务器(Authorization Server)-->>客户端(Client): (H) 返回新访问令牌<br/>(和可选的新刷新令牌)
Note over 客户端(Client),资源服务器(Resource Server): 图2 OAuth 2.0 刷新令牌流程图
图 2 所示的流程包含以下步骤:
(A) 客户端通过向授权服务器进行身份认证,并提交一个授权许可(authorization grant),以请求获取访问令牌。
(B) 授权服务器对客户端进行身份认证,并验证该授权许可;若验证通过,则颁发一个访问令牌和一个刷新令牌。
(C) 客户端向资源服务器发起受保护的资源请求,并在请求中出示访问令牌。
(D) 资源服务器验证该访问令牌;若有效,则处理并响应该请求。
(E) 步骤 (C) 和 (D) 会重复执行,直至访问令牌过期。如果客户端已知访问令牌已过期,则跳至步骤 (G);否则,它将继续发起另一次受保护的资源请求。
(F) 由于访问令牌无效,资源服务器返回一个“令牌无效”错误。
(G) 客户端通过向授权服务器进行身份认证,并提交刷新令牌,以请求一个新的访问令牌。客户端的身份认证要求取决于其客户端类型以及授权服务器的策略。
(H) 授权服务器对客户端进行身份认证,并验证刷新令牌;若验证通过,则颁发一个新的访问令牌(并可选地颁发一个新的刷新令牌)。
步骤 (C)、(D)、(E) 和 (F) 超出了本规范的范围,如第 7 节所述。
1.6. TLS 版本
本规范在使用传输层安全协议(TLS)时,所适用的 TLS 版本(或多个版本)将随时间推移而变化,具体取决于其广泛部署情况以及已知的安全漏洞。
撰写本文档时,TLS 1.2 版本 [RFC5246] 是最新版本,但其部署基础非常有限,可能尚无法被轻松用于实现。相比之下,TLS 1.0 版本 [RFC2246] 是目前部署最广泛的版本,能够提供最广泛的互操作性。
实现可以(MAY)支持其他满足其安全要求的传输层安全机制。
补充:TLS 1.3版本 RFC 8446,现在1.3是最新的版本
1.7. HTTP 重定向
本规范大量使用了 HTTP 重定向机制,即客户端或授权服务器引导资源所有者的用户代理(user-agent)跳转至另一个目标地址。
尽管本规范中的示例使用了 HTTP 302 状态码,但只要能通过用户代理实现此类重定向的任何其他方法都是允许的,并被视为具体的实现细节。
1.8. 互操作性(Interoperability)
OAuth 2.0 提供了一个功能丰富且安全特性明确的授权框架。然而,作为一个高度可扩展、包含大量可选组件的框架,仅凭本规范本身,很可能导致各种无法相互兼容的实现。
此外,本规范对若干必要组件未作完整定义,甚至完全留白(例如:客户端注册机制、授权服务器的功能要求、端点发现方式等)。
若缺乏这些组件,客户端必须针对特定的授权服务器和资源服务器进行手动且专门的配置,才能实现互操作。
本框架在设计之初就明确预期:未来的工作将定义具有约束力的配置规范(prescriptive profiles)和扩展机制,以实现真正适用于万维网规模的完整互操作性。
1.9 记法约定(Notational Conventions)
本规范中的关键词 “MUST”(必须) 、 “MUST NOT”(不得) 、 “REQUIRED”(必需) 、 “SHALL”(应) 、 “SHALL NOT”(不应) 、 “SHOULD”(应该) 、 “SHOULD NOT”(不应该) 、 “RECOMMENDED”(推荐) 、 “MAY”(可以) 和 “OPTIONAL”(可选) ,其解释方式遵循 [RFC2119] 中的定义。
本规范采用 [RFC5234] 中规定的增广巴科斯范式(ABNF)记法。此外,其中的 URI-reference 规则引自《统一资源标识符(URI):通用语法》[RFC3986]。
若干与安全相关的术语应按照 [RFC4949] 中所定义的含义理解。这些术语包括但不限于:
“attack”(攻击)、“authentication”(认证)、“authorization”(授权)、“certificate”(证书)、“confidentiality”(机密性)、“credential”(凭证)、“encryption”(加密)、“identity”(身份)、“sign”(签名)、“signature”(数字签名)、“trust”(信任)、“validate”(验证)和 “verify”(校验)。
除非另有说明,所有协议参数的名称和值均区分大小写。