http://page.renren.com/699032478/note/708597990 (一)背景知识 OAuth 2.0极可能是下一代的“用户验证和受权”标准,目前在国内尚未很靠谱的技术资料。为了弘扬“开放精神”,让业内的人更容易理解“开放平台”相关技术,进而长远地促进国内开放平台领域的发展,笔者特地将OAuth 2.0协议翻译成中文。 目前OAuth 2.0尚未最后定稿,最新的修改版是第11个版本,本文下面的翻译即基于这个第11版本。原文见http://tools.ietf.org/html/draft-ietf-oauth-v2-11。 关于OAuth 2.0的更多背景知识,请参考个人另外一篇文章:http://itgeeker.com/mathml/readpaper?pid=65 (二)术语中英对照表 因为OAuth协议版本较多(1.0,1.0a,2.0等),而且各个版本中的技术术语也各不相同,关于英文技术术语与中文的对应关系,咱们以OAuth 2.0的第11版本中的描述为准。 另外有一些状况,一些英文术语不容易找到广泛接受的汉语释义,翻译过来反而可能引发误解,而英文术语自己可能更容易理解,所以就不考虑对这部分词汇作翻译了。好比,“web service”、“endpoint”、“user-agent”、“URI”、“cookie”等,你只须要知道它是什么就行了。 还有一些特别难于翻译的词汇,好比“profile”,这个词用在协议里,大概表示:协议功能的某个剖面、子集、子视图或轮廓。若是翻译成“视图”,容易让人想到“view”这个词,产生冲突,最后,我在这里创造了一个新词汇:“子态”。 下面是整理出来的重要技术术语的中英对照表: 云计算 —— cloud computing 第三方 —— third-party 应用/程序 —— application 私有证书 —— credential 身份验证 —— authentication 受权 —— authorization 明文 —— clear-text 客户端 —— client {译者注:本文中的客户端与日常所说的“客户端”并不相同,是相对资源服务器和受权服务器来讲的,它可能指第三方应用的服务器程序或客户端程序} 服务器 —— server 资源拥有者 —— resource owner 受保护资源 —— protected resource 资源服务器 —— resource server 访问令牌 —— access token 受权服务器 —— authorization server 访问许可 —— access grant 实体 —— entity 签名 —— signature 刷新令牌 —— refresh token 做用域 —— scope 受权码 —— authorization code 标识符 —— identifier 密钥 —— secret 断言 —— assertion 原生程序 —— native application 子态 —— profile 同源策略 —— same-origin policy 回调 —— callback 自治的 —— autonomous 查询参数部分 —— query component 分段参数部分 —— fragment component 媒体类型 —— media type 厂商特性的 —— vendor-specific 加强型巴科斯范式 —— ABNF 互联网编号分配机构 —— IANA 互联网工程指导组 —— IESG 标准轨道 —— standards-track (三)中文译本 1. 引言 随着分布式web service和云计算的使用愈来愈多,第三方应用须要能访问到一些服务器托管资源。这些资源一般都是受保护的,而且要求使用资源拥有者的私有证书(典型的证书是用户名和密码)进行身份验证。 在传统的基于客户端-服务器的身份验证模型中,客户端为了访问服务器的受保护资源,是使用资源拥有者的私有证书来作身份验证的。为了让第三方应用可以访问受保护资源,资源拥有者必需将他/她/它的私有证书透露给第三方。这引出了不少问题并存在不少局限性: 第三方应用须要用明文保存资源拥有者的私有证书(通常是密码),留做之后再次使用。 虽然密码验证会形成安全隐患,服务器仍然须要支持用密码作身份验证(对称的密码验证)。 第三方应用对资源拥有者的受保护资源得到过多的使用权限,而资源拥有者没有能力限制访问到某个资源子集,限制持续时间,或限制这些资源所能支持的访问方式。 资源拥有者没法在不影响全部第三方的前提下单独撤销某个第三方的访问权限,他/她/它只能经过修改密码来回收全部权限。 OAuth经过将客户端和资源拥有者的角色进行分离来解决这些问题。在OAuth中,客户端(一般不是资源拥有者,而是表明资源拥有者来操做)提出请求来访问由资源拥有者控制并由资源服务器托管的资源,而后获得与资源拥有者不一样的一套私有证书。 客户端并非直接使用资源拥有者的私有证书来访问受保护资源,而是获得一个访问令牌——一个表明某一特定做用域、持续时间和其它属性的字符串{译者注:很是重要的一个概念,英文叫access token}。访问令牌由受权服务器在资源拥有者的授意下分发给第三方客户端。客户端使用访问令牌来访问由资源服务器托管的受保护资源。 例如,一个web用户(资源拥有者)可以准许一个打印服务(客户端)访问她存储在另外一个照片共享服务(资源服务器)中的照片,而不用将她的用户名和密码透露给这个打印服务。她在一个被该照片分享服务信任的身份验证服务(受权服务器)上完成验证,而这个验证服务会将特定于委托服务的私有证书(令牌)分发给原打印服务。 基于资源服务器对安全的需求,访问令牌能够有不一样的格式、结构和使用方式(例如密码学特性)。访问令牌的属性和用以访问受保护资源的方式不在本规范的规定范围以内,而是由相关的其它规范来定义。受权服务器和资源服务器之间的交互方式不在本规范的规定范围以内。 1.1. 符号规范 这篇文档中的关键词“必须”、“必定不能”、“要求”、“会”、“不会”、“应该”、“不该该”、“建议”、“能够”、“可选的”,听从[RFC2119]中的解释。 这篇文档使用出自[I-D.ietf-httpbis-p1-messaging]的加强型巴科斯范式(ABNF)标记法。另外,介绍一些规则定义的出处:URI-Reference出自[RFC3986];OWS、RWS和quoted-string出自[I-D.ietf-httpbis-p1-messaging]。 除非特别提到,不然全部协议参数的名字和值都是大小写敏感的。 1.2. 专业术语解释 受保护资源:可以使用OAuth请求获取的访问限制性资源。 资源服务器:可以接受和响应受保护资源请求的服务器。 客户端:获取受权和发送受保护资源请求的应用。 资源拥有者:可以对受保护资源进行访问许可控制的实体。 终端用户:起到资源拥有者角色的用户。 令牌:分发给客户端的表明访问受权的字符串。一般这个字符串对客户端来讲是不透明的。令牌表明资源拥有者许可的访问做用域和持续时间,并由资源服务器和受权服务器强制保证。这个令牌能够表明一个标识符,用于检索受权信息,或以一种可验证的方式自包含受权信息(即一个包含数据和签名的令牌字符串)。令牌可能只表明纯粹的访问能力。而为了让客户端使用令牌,也可能须要一些多余的特定验证证书。 访问令牌:被客户端用来表明资源拥有者发送验证请求的令牌。 刷新令牌:被客户端用来获取新的访问令牌的令牌,而不用资源拥有者的参与。 受权码:一个短时间令牌,表明终端用户的受权。受权码用于获取一个访问令牌和一个刷新令牌。 访问许可:用于描述中间形式的私有证书(如终端用户的密码或受权码)的一个通用词汇,表明资源拥有者的受权。客户端使用访问许可来获取访问令牌。经过将各类形式的访问许可都交换成访问令牌,资源服务器只须要支持一种验证机制。 受权服务器:可以成功验证资源拥有者和获取受权,并在此以后分发令牌的服务器。受权服务器能够和资源服务器是同一个服务器,也能够是不一样的实体。单独一个受权服务器能够为多个资源服务器分发令牌。 终端用户受权endpoint:受权服务器上可以验证终端用户并获取受权的HTTP endpoint。终端用户受权endpoint在第4节详细描述。 令牌endpoint:受权服务器上可以分发令牌和刷新过时令牌的HTTP endpoint。令牌endpoint在第5节详细描述。 客户端标识符:分发给客户端的惟一标识,用于客户端向受权服务器标识本身。客户端标识符能够有一个对应的密钥。客户端标识符在第3节详细描述。 1.3. 概述 OAuth为客户端提供了一种表明资源拥有者访问受保护资源的方法。在客户端访问受保护资源以前,它必须先从资源拥有者获取受权(访问许可),而后用访问许可交换访问令牌(表明许可的做用域、持续时间和其它属性)。客户端经过向资源服务器出示访问令牌来访问受保护资源。 访问令牌提供了一个抽象层,将不一样的受权结构(如用户名密码、断言)替换成资源服务器能够理解的单一令牌。这种抽象使得分发短时间有效的访问令牌成为可能,也使得资源服务器没必要理解多种多样的受权机制。 图1: 抽象的协议流程 图1所示的抽象流程协议的整体架构,它包含下列步骤: (A) 客户端从资源拥有者那里请求受权。受权请求可以直接发送给资源拥有者,或者间接地经过受权服务器这样的中介,然后者更为可取。 (B) 客户端收到一个访问许可,它表明由资源服务器提供的受权。 (C) 客户端使用它本身的私有证书到受权服务器上验证,并出示访问许可,来请求一个访问令牌。 (D) 受权服务器验证客户端私有证书和访问许可的有效性,若是验证经过则分发一个访问令牌。 (E) 客户端经过出示访问令牌向资源服务器请求受保护资源。 (F) 资源服务器验证访问令牌的有效性,若是验证经过则响应这个资源请求。 1.4 访问许可 访问许可表明资源拥有者提供的受权。访问许可的类型取决于客户端使用的获取方式和受权服务器所支持的方式。 1.4.1 受权码 受权码是经过将终端用户引导到受权服务器而得到的一种访问许可。受权服务器验证终端用户,得到受权,而后向客户端分发一个受权码。由于终端用户只在受权服务器上进行验证,因此终端用户的密码历来不用分享给客户端。 当客户端经过一个user-agent同终端用户进行交互的时候,受权码这种访问许但是很合适的。 图2: 获取受权码 图2所示的受权码获取流程包含下列步骤: (A) 客户端经过将终端用户的user-agent引导到受权服务器的终端用户受权endpoint来发起这个流程。客户端传入标识符、请求做用域、本地状态,和一个重定向URI(在访问被许可或被拒绝后受权服务器会从新将user-agent引导回这个URI)。 (B) 受权服务器验证终端用户的身份(经过user-agent),而且肯定终端用户是许可仍是拒绝了客户端的访问请求。 (C) 若是访问被许可,受权服务器会使用重定向URI将user-agent引导回客户端。受权服务器传回一个受权码给客户端,用于进一步获取访问令牌。 一旦客户端得到了受权码,它会到受权服务器上去作验证(使用客户端私有证书)并出示受权码(访问许可),以借此请求一个访问令牌。 在客户端没法维护它本身的私有证书的状况下(如原生程序或用某种user-agent脚本实现的程序),受权服务器在(C)步直接给客户端分发一个访问令牌,而再也不分发一个受权码。 得到受权码的过程在第4节详述。 1.4.2 资源拥有者密码证书 资源拥有者密码证书(例如用户名和密码)能够直接用做访问许可来获取访问令牌。这种私有证书只应该在如下两种状况下使用:当在资源拥有者和客户端之间有很强的信任关系的时候(例如,资源拥有者的计算机操做系统,或具备很高特权的程序),以及当其它访问许可类型(如受权码)不可用的时候。 即便这种许可类型须要客户端直接访问资源拥有者的私有证书,资源拥有者的私有证书也只是在一个请求中使用,并交换成访问令牌。与[RFC2617]定义的HTTP Basic验证机制不一样,这种许可类型再也不须要客户端存储资源拥有者的私有证书以备往后使用。 图3: 获取资源拥有者密码证书 在图3中,客户端直接从资源拥有者请求受权。当资源拥有者是一个终端用户时,客户端一般的作法是提示终端用户输入用户名和密码。 1.4.3 客户端私有证书 当受权做用域限制在客户端所控制的受保护资源或以前与受权服务器约定好的受保护资源时,客户端自己的私有证书可被用做访问许可。客户端私有证书用做访问许可的典型例子是,当客户端表明它本身执行操做时(客户端同时也是资源拥有者)。 1.4.4 刷新令牌 访问令牌的生命周期一般比资源拥有者授予的要短一些。当分发一个访问令牌时,受权服务器能够同时传回一个刷新令牌,在当前访问令牌超时后,客户端能够用这个刷新令牌从新获取一个访问令牌。当请求新的访问令牌时,刷新令牌担当起访问许可的角色。使用刷新令牌,再也不须要再次与资源拥有者交互,也不须要存储原始的访问许可来得到访问令牌和刷新令牌。 图4: 刷新访问令牌 图4所示的刷新令牌流程包含下列步骤: (A) 客户端经过使用它本身的私有证书在受权服务器上验证,并出示一个访问许可。 (B) 受权服务器验证客户端私有证书和访问许可的有效性,若是经过则分发一个访问令牌和刷新令牌。 (C) 客户端经过出示访问令牌向资源服务器请求受保护资源。 (D) 资源服务器验证访问令牌的有效性,若是经过,则相应这个请求。 (E) 步骤(C)(D)不停重复,直到访问令牌过时。若是客户端不知道访问令牌过时,它会再请求一次受保护资源。不然,跳到步骤(G)。 (F) 由于访问令牌是无效的(过时了),资源服务器返回一个无效令牌错误。 (G) 客户端经过使用它的私有证书在受权服务器上验证并出示刷新令牌(用做访问许可),来请求一个新的访问令牌。 (H) 受权服务器验证客户端私有证书的有效性,若是经过则分发一个新的访问令牌(也可能还有一个刷新令牌)。 1.4.5 断言 断言在OAuth和其它信任框架之间架起一座桥梁。它们容许客户端利用现成的信任关系来获取访问令牌。一个断言所表明的访问许可取决于断言类型、断言内容,以及断言被分发的方式,而这些内容不在本规范的规定范围以内。 断言能够用在协议扩展模型的部分,它为受权服务器提供了一种支持其它访问许可类型的方式。 2. 客户端的各类子态 2.1 Web Server子态 Web Server子态适用于有能力与终端用户的user-agent(一般是浏览器)交互并可以从受权服务器接收(经过重定向)请求(即有能力担当HTTP服务器的角色)的客户端。 图5: Web Server流程 图5所示的web server流程包含下列步骤: (A) 如第4节所述,web客户端经过将终端用户的user-agent重定向到受权服务器来发起这个流程。客户端传入它的客户端标识符、请求做用域、本地状态和一个重定向URI,在访问被许可(或被拒绝)后受权服务器会从新将终端用户引导回这个URI。 (B) 受权服务器验证终端用户(借助于user-agent),并肯定终端用户是否许可客户端的访问请求。 (C) 假定终端用户许可了此次访问,受权服务器会将user-agent重定向到以前提供的重定向URI上去。受权服务器为客户端传回一个受权码作获取访问令牌之用。 (D) 如第5节所述,客户端经过验证并传入上一步取得的受权码从受权服务器请求一个访问令牌。 (E) 受权服务器验证客户端私有证书和受权码的有效性并返回访问令牌。 2.2 User-Agent子态 User-Agent子态适用于常驻user-agent的客户端应用,典型的例子是用诸如JavaScript语言编写并运行在浏览器的程序。这些客户端不能保存客户端私有证书,而且客户端的验证基于user-agent的同源策略。 在其它子态中,客户端对于终端用户的受权和访问令牌使用分开的不一样请求来完成,而与之不一样的是,在user-agent子态中,客户端以HTTP重定向的方式在终端用户受权请求的结果中获取到访问令牌。客户端请求受权服务器将user-agent重定向到另外一个web服务器或user-agent能访问到的本地资源,并且user-agent有能力从响应信息中提取出访问令牌并传给客户端。 这种user-agent子态并不使用客户端密钥,由于客户端执行程序常驻于终端用户的计算机或设备上,这使得客户端密钥能够被访问或收集到。由于访问令牌被编码到重定向URI中,因此它可能会暴露给终端用户和常驻计算机或设备上的其它应用。 图6: User-Agent流程 图6所示的user-agent流程包含下列步骤: (A) 如第5节所述,客户端将user-agent引导到终端用户受权endpoint。客户端传入它的客户端标识符、请求做用域、本地状态和一个重定向URI,在访问被许可(或被拒绝)后受权服务器会从新将终端用户引导回这个URI。 (B) 受权服务器验证终端用户(经过user-agent)并确认终端用户是许可仍是拒绝了客户端的访问请求。 (C) 若是终端用户许可了此次访问,那么受权服务器会将user-agent引导到以前提供的重定向URI。重定向URI会在URI片段{译者注:URI片段是指URI中#号以后的内容}中包含访问令牌。 (D) user-agent响应重定向指令,向web服务器发送不包含URI片段的请求。user-agent在本地保存URI片段。 (E) web服务器返回一个web页面(一般是嵌入了脚本的HTML网页),这个页面可以访问完整的重定向URI,它包含了由user-agent保存的URI片段,同时这个页面可以将包含在URI片段中的访问令牌(和其它参数)提取出来。 (F) user-agent在本地执行由web服务器提供的脚本,该脚本提取出访问令牌并将它传递给客户端。 2.3 原生程序 原生程序是做为原生代码运行在终端用户计算机或设备上的客户端(即,在user-agent以外运行或做为一个桌面程序)。这些客户端一般有能力与终端用户的user-agent交互(或嵌入user-agent),可是在这些交互如何影响终端用户体验的方式上受到限制。在不少状况下,原生程序没法直接从服务器接收回调请求(例如,防火墙、操做系统限制)。 基于不一样的需求和指望的终端用户体验,原生程序客户端能够用不一样的方式实现。原生程序客户端能够: 如第4节所述,经过启动一个外部user-agent来访问终端用户受权endpoint。客户端能够经过下面的方式捕获响应文本:提供一个具备自定义URI scheme{译者注:URI scheme就是一个URI里面的第一部分,即冒号前面的部分}的重定向URI(在操做系统上注册过以便调用客户端应用),或者提供一个指向在客户端控制下的服务器资源的重定向URI,这使得响应文本对客户端可见(例如,使用窗口标题或在user-agent外面能够访问到的其它位置)。 如第4节所述,经过嵌入一个user-agent来访问终端用户受权endpoint。客户端经过与嵌入的user-agent直接通讯获取到响应文本。 提示终端用户输入密码,使用密码直接得到一个访问令牌。一般来说,这是一种不推荐的方式,由于它将终端用户的密码直接交给了第三方客户端,而客户端不得不用明文存储密码。它还要求服务器支持基于密码的身份验证。 当在启动外部浏览器和嵌入的user-agent之间进行选择时,开发者应该考虑下列因素: 外部浏览器可能会提升完成比率,由于终端用户可能已经登陆过了而不须要从新进行身份验证。 嵌入的user-agent一般能提供更好的用户流程,由于它没必要切换上下文并打开新窗口。 嵌入的user-agent对安全提出了挑战,由于用户在一个没法辨别的窗口之中进行身份验证,而不像不少user-agent那样能提供可视化的保护。 2.4 自治态 自治客户端使用现成的信任关系或框架来创建受权。基于自治客户端的需求和他们所依赖的现存信任框架,自治客户端能够用不一样的方式实现。自治客户端能够: 经过使用客户端私有证书与受权服务器进行验证,从而得到访问令牌。访问令牌的做用域局限于受客户端控制的受保护资源,或者其它资源拥有者与受权服务器预先约定的资源。 使用现存的某种访问许可,它被表达成受权服务器所支持的某种断言格式。使用断言须要客户端从一个断言发行方得到一个断言(如SAML[OASIS.saml-core-2.0-os]断言)或本身分发一个断言。断言的格式、得到断言的过程,以及验证断言的方法,由断言发行方和受权服务器定义,不在本规范的规定范围以内。 3. 客户端私有证书 当与受权服务器进行交互时,客户端使用一个私有证书集合来标识本身,这个证书集合包含一个客户端标识符和用于客户端身份验证的其它一些属性。客户端得到私有证书的方式不在本规范的规定范围以内,不过这一般都包含一个在受权服务器上注册的过程。 考虑到一些客户端的本质特性,在与客户端没有确立信任关系的前提下,受权服务器不该该对客户端密钥的私密性作出任何假设。受权服务器不该该向没有能力对密钥进行秘密保存的客户端分发密钥。 受权服务器可使用任一合适的私有证书集合和验证机制来对客户端进行身份验证。客户端必定不能在一个请求中使用多个私有证书集合和验证机制。 3.1 客户端密码证书 客户端密码证书使用一个共享的对称密钥来验证客户端。客户端标识符和密码被包含在请求当中,使用[RFC2617]定义的HTTP Basic验证机制,将客户端标识符做为用户名(username)并将客户端密码做为密码(password)来传送。 例如(换行符只用于显示目的): POST /token HTTP/1.1 Host: server.example.com Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW Content-Type: application/x-www-form-urlencoded grant_type=authorization_code&code=i1WsRn1uB1& redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb 做为可选方式,客户端可使用下列参数将密码包含在请求体(request body)中: client_id 必需参数。客户端标识符。 client_secret 必需参数。客户端密钥。 例如(换行符只用于显示目的): POST /token HTTP/1.1 Host: server.example.com Content-Type: application/x-www-form-urlencoded grant_type=authorization_code&client_id=s6BhdRkqt3& client_secret=gX1fBat3bV&code=i1WsRn1uB1& redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb 受权服务器必须可以使用请求参数和HTTP Basic验证协议两种方式接受客户端私有证书。受权服务器能够支持更多适合于密码证书传输的验证机制。 3.2 客户端断言证书 客户端断言证书用于不宜使用密码(明文共享对称密钥)或密码没法为客户端验证提供足够安全性的状况。在这样的状况下,常见的作法是使用诸如HMAC或数字签名之类不须要发送明文密钥的其它机制。客户端断言证书提供了一种扩展机制,可以使用被受权服务器所支持的某种断言格式进行客户端身份验证。 使用断言须要客户端从一个断言发行方得到一个断言(如SAML[OASIS.saml-core-2.0-os]断言)或本身分发一个断言。断言的格式、得到断言的过程,以及验证断言的方法,由断言发行方和受权服务器定义,不在本规范的规定范围以内。 当使用客户端断言时,客户端传送下列参数: client_assertion_type 必需参数。由受权服务器定义的断言格式。这个值必须是一个绝对URI。 client_assertion 必需参数。客户端断言。 例如,客户端使用一个SAML 2.0断言发送以下访问令牌请求来验证本身(换行符只用于显示目的): POST /token HTTP/1.1 Host: server.example.com Content-Type: application/x-www-form-urlencoded grant_type=authorization_code&code=i1WsRn1uB1& client_assertion=PHNhbWxwOl[...omitted for brevity...]ZT4%3D& client_assertion_type= urn%3Aoasis%3Anames%sAtc%3ASAML%3A2.0%3Aassertion& redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb 当使用一个客户端断言和一个受权码得到一个访问令牌的时候,须要一个机制在用于获取受权码的“client_id”参数值和客户端断言之间完成映射。这个机制不在本规范的规定范围以内,但对于与受权码结合使用的任何客户端断言类型都必须明确指明。 对于那些使用客户端断言证书但不包含可以提供下列信息的HMAC或签名值的访问令牌请求,受权服务器必须拒绝响应: 指明这个断言是专门分发给当前接收endpoint来处理的(通常是经过一个包含接收endpoint标识符的audience或recipient值)。 标识出分发断言的实体(通常是经过一个issuer值)。 用一个绝对时间标识出断言在什么时候过时(通常是经过一个包含UTC日期/时间值的过时值)。受权服务器必须拒绝过时的断言。 4. 得到终端用户受权 在客户端可以访问一个受保护资源以前,它必须首先从终端用户那里获取受权。为了得到终端用户受权,客户端须要将终端用户引导到终端用户受权endpoint。一旦得到受权,终端用户的访问许可会被表示成一个受权码,客户端可以使用它去获取一个访问令牌。 在终端用户受权endpoint上,终端用户首先在受权服务器上完成身份验证,而后容许或者拒绝当前访问请求。受权服务器验证用户的方式(例如,用户名和密码登陆,OpenID,会话cookie)和受权服务器获取终端用户受权的方式,以及是否使用诸如TSL之类的安全通道,不在本规范的规定范围以内。然而,受权服务器必需要首先验证终端用户的身份。 终端用户受权endpoint的位置可以在服务器文档中找到。终端用户受权endpoint的URI能够按照[RFC3986]第3节的定义包含一个查询参数部分,它们在添加其它参数时必须被保留。 既然对于终端用户受权endpoint的请求会致使用户身份验证和敏感信息的传输,受权服务器应该要求在向终端用户受权endpoint发送请求的时候使用诸如TLS之类的传输层安全机制。 4.1 受权请求 为了将终端用户的user-agent引导到受权服务器,客户端将下列参数添加到终端用户受权endpoint URI的查询参数部分,并使用如[W3C.REC-html401-19991224]所定义的“application/x-www-form-urlencoded”格式构建起一个请求URI,以下定义: response_type 必需参数。请求的响应中:一个访问令牌、一个受权码,或二者都有。请求访问令牌参数值必须设为“token”,请求受权码参数值必须设为“code”,或者使用参数值为“code_and_token”同时请求二者。受权服务器可能拒绝提供这些响应类型中的一种或多种。 client_id 必需参数。如第3节所述的客户端标识符。 redirect_uri 必需参数,除非经过其它方式在客户端和受权服务器之间已经肯定了一个重定向URI。这是当终端用户的受权步骤完成时受权服务器将要把user-agent重定向到的一个绝对URI。受权服务器应该要求客户端预先注册它们的重定向URI。 scope 可选参数。访问请求的做用域,以空格隔开的字符串列表来表示。“scope”参数的值由受权服务器定义。若是这个值包含多个空格隔开的字符串,那么它们的顺序不分前后,并且每一个字符串都为请求的做用域增长一个新的访问范围。 state 可选参数。被客户端用来在请求和回调之间维护状态的值,对受权服务器来讲是不透明的。受权服务器在将user-agent重定向回客户端时传回这个值。 客户端经过user-agent使用HTTP重定向响应,或者其它可用的方式,将终端用户引导到构建好的URI上。对于终端用户受权endpoint,受权服务器必须支持HTTP的“GET”方法,也能够支持使用“POST”方法。 例如,客户端引导终端用户的user-agent使用传输层安全机制发送下列HTTP请求(换行符只用于显示目的): GET /authorize?response_type=code&client_id=s6BhdRkqt3& redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1 Host: server.example.com 若是客户端已经在受权服务器上预先注册了一个重定向URI,受权服务器必须保证收到的重定向URI与当前客户端标识符所对应的注册URI相匹配。受权服务器不该该将user-agent重定向到没有注册过的或不信任的URI,以免endpoint被用做一个公开的转向器。若是没有可用的有效重定向URI,受权服务器应该将发生的错误报告给用户[[提供如何执行匹配操做的建议]]。 没有值的参数必须被当作它们在请求中不存在同样。受权服务器应该忽略识别不了的请求参数。 受权服务器对请求进行验证以保证全部必需参数都存在并有效。若是请求是无效的,受权服务器将使用重定向URI把user-agent重定向回客户端,而且URI后面加上适当的错误码,如4.3节所述。 受权服务器验证终端用户的身份并得到一个受权决定(经过询问用户或经过其它方式承认)。当一个决定被作出后,受权服务器将终端用户的user-agent引导到客户端提供的重定向URI,这个重定向或者使用HTTP重定向响应,或者经过终端用户user-agent的其它可用的方式。 4.2 受权响应 若是终端用户许可了访问请求,受权服务器会分发一个访问令牌,或一个受权码,或者二者都有,而且经过将下列参数添加到重定向URI将这些分发结果传递给客户端(以下所述)。 code 若是响应类型是“code”或“code_and_token”则是必需的,不然必定不能包含这个参数。表示由受权服务器产生的受权码。受权码应该在分发后迅速过时,以下降泄露风险。客户端必定不能重用同一个受权码。若是一个受权码被屡次使用,受权服务器可能撤销以前基于这个受权码分发的全部令牌。受权码与客户端标识符和重定向URI相绑定。 access_token 若是响应类型是“token”或“code_and_token”则是必需的,不然必定不能包含这个参数。表示由受权服务器分发的访问令牌。 token_type 若是响应中包含一个访问令牌则是必需的。表示分发的令牌类型。令牌类型告诉客户端一个信息,即当访问一个受保护资源时访问令牌应该如何被使用,如6.1节所述。 expires_in 可选参数。若是包含访问令牌参数,则表示访问令牌生命周期的秒数。例如,“3600”表示自响应被受权服务器产生的时刻起,访问令牌将在一小时后过时。 scope 可选参数。若是包含访问令牌参数,则表示访问令牌的做用域,表示为一个空格隔开的字符串列表。“scope”参数的值由受权服务器定义。若是这个值包含多个空格隔开的字符串,那么它们的顺序不分前后,并且每一个字符串都为请求的做用域增长一个新的访问范围。若是请求到的做用域不一样于客户端申请的做用域,受权服务器应该传回这个参数。 state 若是“state”参数在客户端受权请求中存在,则这个参数是必需的。须要精确地设置成从客户端接收到的值。 受权服务器在重定向URI上添加参数的方式取决于客户端在受权请求中请求的响应类型,由“response_type”参数指定。 若是响应类型是“code”,受权服务器使用如[W3C.REC-html401-19991224]所定义的“application/x-www-form-urlencoded”格式添加参数到重定向URI的查询参数部分。 例如,受权服务器经过发送下列HTTP响应将终端用户的user-agent进行重定向: HTTP/1.1 302 Found Location: https://client.example.com/cb?code=i1WsRn1uB1 若是响应类型是“code”或“code_and_token”,受权服务器使用如[W3C.REC-html401-19991224]所定义的“application/x-www-form-urlencoded”格式添加参数到重定向URI的分段参数部分。 例如,受权服务器经过发送下列HTTP响应将终端用户的user-agent进行重定向(URI换行符只用于显示目的): HTTP/1.1 302 Found Location: http://example.com/rd#access_token=FJQbwq9& token_type=example&expires_in=3600 客户端应该忽略没法识别的响应参数。从受权服务器接收到的令牌和其它参数值的大小,本规范未做定义。客户端应该避免对参数值大小作任何假设。服务器应该对它们所分发的任何参数值的指望大小作出文档说明。 4.3 错误响应 若是终端用户拒绝了访问请求,或者因为除了缺乏或无效重定向URI以外的其它缘由而致使请求失败,受权服务器使用如[W3C.REC-html401-19991224]所定义的“application/x-www-form-urlencoded”格式添加下列参数到重定向URI的查询参数部分以通知客户端: error 必需参数。如4.3.1节所述的一个错误码。 error_description 可选参数。提供额外信息的一段人类可读的文字,用来帮助理解和解决发生的错误。 error_uri 可选参数。指明了一我的类可读的网页URI,带有关于错误的信息,用来为终端用户提供与错误有关的额外信息。 state 若是“state”参数在客户端受权请求中存在,则这个参数是必需的。须要精确地设置成从客户端接收到的值。 例如,受权服务器经过发送下列HTTP响应将终端用户的user-agent进行重定向: HTTP/1.1 302 Found Location: https://client.example.com/cb?error=access_denied 若是因为缺乏或无效重定向URI而致使请求失败,受权服务器应该通知终端用户这个错误,而必定不能将终端用户的user-agent重定向到这个无效的重定向URI。 4.3.1 错误码 受权服务器在错误响应中包含下列错误码之一: invalid_request 请求缺乏某个必需参数,包含一个不支持的参数或参数值,或者格式不正确。 invalid_client 提供的客户端标识符是无效的。 unauthorized_client 客户端没有权限使用该请求的响应类型。 redirect_uri_mismatch 提供的重定向URI与预先注册的值不匹配。 access_denied 终端用户或受权服务器拒绝了请求。 unsupported_response_type 请求的响应类型不为受权服务器所支持。 invalid_scope 请求的做用域是无效的、未知的,或格式不正确的。 [[增长扩展错误码的机制]] 5. 获取访问令牌 客户端经过在受权服务器上验证并出示它的访问许可(表示成受权码、资源拥有者私有证书、断言或刷新令牌的形式)来获取一个访问令牌。 既然对于令牌endpoint的请求会致使在HTTP请求和响应中传输明文证书,受权服务器必须要求在向令牌endpoint发送请求的时候使用传输层安全机制。服务器必需支持[RFC5246]所定义的TLS 1.2,而且可能支持额外的传输层安全机制。 客户端经过向令牌endpoint发送一个HTTP POST请求来获取一个访问令牌。令牌endpoint的位置可以在服务器文档中找到。令牌endpoint URI可能包含一个查询参数部分。 客户端经过在请求中添加客户端私有证书与受权服务器进行验证,如第3节所述。当客户端标识符不重要的时候(例如匿名客户端),或当客户端标识符经过其它方式肯定的时候(例如使用一个断言访问许可),受权服务器可能容许不经验证的访问令牌请求。 客户端经过在HTTP请求的entity-body中使用“application/x-www-form-urlencoded”格式包含下列参数,来构建请求: grant_type 必需参数。在请求中所包含的访问许可类型。它的值必须是“authorization_code”、“password”、“refresh_token”、“client_credentials”或一个用来标识被受权服务器所支持的断言类型的绝对URI。 scope 可选参数。访问请求的做用域,表达为一个由空格隔开的字符串列表。“scope”参数的值由受权服务器定义。若是这个值包含多个空格隔开的字符串,那么它们的顺序不分前后,并且每一个字符串都为请求的做用域增长一个新的访问范围。若是使用的访问许可已经表明了一个许可做用域(例如,受权码、断言),那么请求的做用域必须等于或少于以前许可的做用域,若是缺乏这个参数就认为是等于以前的许可做用域。 另外,对于5.1节列出的某个访问许可类型,客户端必须包含合适的参数。 没有值的参数必须被当作它们在请求中不存在同样。受权服务器应该忽略识别不了的请求参数。 5.1 访问许可类型 客户端使用一个受权码、资源拥有者密码证书、客户端私有证书、刷新令牌或断言来请求一个访问许可。 5.1.1 受权码 客户端使用“authorization_code”访问许可类型和下列参数传入受权码: code 必需参数。从受权服务器接收到的受权码。 redirect_uri 必需参数。在最初请求中使用的重定向URI。 例如,客户端经过如第3节所述的“client_secret”参数包含客户端私有证书,并使用传输层安全机制,来发送下列HTTP请求(换行符只用于显示目的): POST /token HTTP/1.1 Host: server.example.com Content-Type: application/x-www-form-urlencoded grant_type=authorization_code&client_id=s6BhdRkqt3& client_secret=gX1fBat3bV&code=i1WsRn1uB1& redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb 受权服务器必须: 验证客户端私有证书(若是存在)并保证它们与受权码匹配。 验证受权码和重定向URI都是有效的,而且与存储的关联关系相匹配。 若是请求有效,受权服务器分发一个成功响应,如5.2节所述。 5.1.2 资源拥有者密码证书 客户端使用“password”访问许可类型和下列参数传入资源拥有者密码证书:[[增长对于用户名和密码的国际化考虑]] username 必需参数。资源拥有者的用户名。 password 必需参数。资源拥有者的密码。 例如,客户端经过如第3节所述的“client_secret”参数包含客户端私有证书,并使用传输层安全机制,来发送下列HTTP请求(换行符只用于显示目的): POST /token HTTP/1.1 Host: server.example.com Content-Type: application/x-www-form-urlencoded grant_type=password&client_id=s6BhdRkqt3& client_secret=47HDu8s&username=johndoe&password=A3ddj3w 受权服务器必须验证客户端私有证书(若是存在)和终端用户私有证书,并且若是发现有效则必须发布一个访问令牌响应,如5.2节所述。 5.1.3 客户端私有证书 客户端能够仅仅使用它的客户端私有证书来请求一个访问令牌,即便用“client_credentials”访问许可类型。当省略一个显式的访问许可时,客户端是在请求访问它所控制的受保护资源,或另外一个资源拥有者以前与受权服务器约定好的受保护资源(约定方式不在本规范的规定范围以内)。 5.1.4 刷新令牌 客户端使用“refresh_token”访问许可类型和下列参数传入刷新令牌: refresh_token 必需参数。与待刷新的访问令牌相关联的刷新令牌。 例如,客户端经过如第3节所述的“client_secret”参数包含客户端私有证书,并使用传输层安全机制,来发送下列HTTP请求(换行符只用于显示目的): POST /token HTTP/1.1 Host: server.example.com Content-Type: application/x-www-form-urlencoded grant_type=refresh_token&client_id=s6BhdRkqt3& client_secret=8eSEIpnqmM&refresh_token=n4E9O119d 受权服务器必须验证客户端私有证书(若是存在),验证刷新令牌是否有效,以及验证资源拥有者的受权是否仍然有效。若是请求有效,受权服务器则发布一个访问令牌响应,如5.2节所述。受权服务器能够发布一个新的刷新令牌,在这种状况下,客户端必须丢弃旧的刷新令牌而且用新的访问令牌替换。 5.1.5 断言 客户端使用一个绝对URI(由受权服务器定义)做为“grant_type”参数的值指定断言格式,并添加下列参数,来传入一个断言: assertion 必需参数。断言。 例如,客户端使用传输层安全机制来发送下列HTTP请求,且客户端验证经过断言来完成(换行符只用于显示目的): POST /token HTTP/1.1 Host: server.example.com Content-Type: application/x-www-form-urlencoded grant_type=urn%3Aoasis%3Anames%3Atc%3ASAML%3A2.0%3Aassertion& assertion=PHNhbWxwOl[...omitted for brevity...]ZT4%3D 受权服务器必须验证客户端私有证书(若是存在)和断言,并且若是发现有效则必须发布一个访问令牌响应,如5.2节所述。受权服务器不该该分发一个刷新令牌(而是应该要求客户端使用相同的或新的断言)。 受权服务器应该分发具备有限生命周期的访问令牌,而且要求客户端使用仍然有效的同一个断言来请求新的访问令牌,从而完成对令牌的刷新。 5.2 访问令牌响应 在接收到并验证过来自客户端的一个有效且经受权的访问令牌请求以后,受权服务器分发访问令牌和可选的刷新令牌,而且经过一个200(OK)状态码在HTTP响应的entity body中添加下列参数来构造响应: 令牌响应包含下列参数: access_token 必需参数。由受权服务器分发的访问令牌。 token_type 必需参数。分发的令牌类型。令牌类型告诉客户端一个信息,即当访问一个受保护资源时访问令牌应该如何被使用,如6.1节所述。 expires_in 可选参数。访问令牌生命周期的秒数。例如,“3600”表示自响应被受权服务器产生的时刻起,访问令牌将在一小时后过时。 refresh_token 可选参数。用来获取新的访问令牌的刷新令牌,如5.1.4节所述使用相同的终端用户访问许可。当访问许可类型是一个断言或一个客户端私有证书集合时,受权服务器不该该分发一个刷新令牌。 scope 可选参数。访问令牌的做用域,表示为一个空格隔开的字符串列表。“scope”参数的值由受权服务器定义。若是这个值包含多个空格隔开的字符串,那么它们的顺序不分前后,并且每一个字符串都为请求的做用域增长一个新的访问范围。若是请求到的做用域不一样于客户端申请的做用域,受权服务器应该传回这个参数。 参数包含在HTTP响应的entity body中,使用[RFC4627]定义的“application/json”媒体类型。经过在最高结构层次上添加每一个参数,将它们序列化成一个JSON结构。参数名和字符串值都表示成JSON字符串。数字值表示成JSON数字。 在任何包含令牌、密钥或其它敏感信息的响应中,受权服务器必须在“Cache-Control”响应头部字段中传入一个“no-store”的值。 例如: HTTP/1.1 200 OK Content-Type: application/json Cache-Control: no-store { "access_token":"SlAV32hkKG", "token_type":"example", "expires_in":3600, "refresh_token":"8xLOxBtZp8" } 客户端应该忽略没法识别的响应参数。从受权服务器接收到的令牌和其它参数值的大小,本规范未做定义。客户端应该避免对参数值大小作任何假设。服务器应该对它们所分发的任何参数值的指望大小作出文档说明。 5.3 错误响应 若是令牌请求是无效的或未经受权的,受权服务器经过在HTTP响应的entity body中添加下列参数并使用“application/json”媒体类型来构造响应: error 必需参数。如4.3.1节所述的一个错误码。 error_description 可选参数。提供额外信息的一段人类可读的文字,用来帮助理解和解决发生的错误。 error_uri 可选参数。指明了一我的类可读的网页URI,带有关于错误的信息,用来为终端用户提供与错误有关的额外信息。 例如: HTTP/1.1 400 Bad Request Content-Type: application/json Cache-Control: no-store { "error":"invalid_request" } 若是客户端经过“Authorization”请求头部字段使用HTTP验证机制这种方式提供了无效的私有证书,那么受权服务器必须用HTTP 401(Unauthorized)状态码进行响应。不然,受权服务器应该用HTTP 400(Bad Request)状态码进行响应。 5.3.1 错误码 受权服务器在错误响应中传回下列错误码之一: invalid_request 请求缺乏某个必需参数,包含一个不支持的参数或参数值,参数重复,包含多个私有证书,使用了多种验证客户端的机制,或者请求格式不正确。 invalid_client 提供的客户端标识符是无效的,客户端验证失败,客户端不包含私有证书,提供了多个客户端私有证书,或使用了不支持的证书类型。 unauthorized_client 通过验证的客户端没有权限使用提供的访问许可类型。 invalid_grant 提供的访问许但是无效的、过时的或已撤销的(例如,无效的断言,过时的受权令牌,错误的终端用户密码证书,或者不匹配的受权码和重定向URI)。 unsupported_grant_type 包含的访问许可——它的类型或其它属性——不被受权服务器所支持。 invalid_scope 请求的做用域是无效的、未知的、格式不正确的,或超出了以前许可的做用域。 [[增长扩展错误码的机制]] 6. 访问受保护资源 客户端经过向资源服务器出示一个访问令牌来访问受保护资源。资源服务器必须验证访问令牌,保证它没有过时而且它的做用域覆盖了请求的资源。被资源服务器用来验证访问令牌的方式不在本规范的规定范围以内,可是它一般须要在资源服务器和受权服务器之间进行交互或配合。 客户端利用访问令牌来验证资源服务器的方式取决于由受权服务器分发的访问令牌类型。 6.1 访问令牌类型 [[增长令牌类型的解释,可能包含指定其它规范的连接]] 6.2 WWW-Authenticate响应头部字段 若是对于受保护资源的请求不包含验证证书,包含一个无效的访问令牌,或格式不正确,那么资源服务器必须包含一个HTTP “WWW-Authenticate”响应头部字段。这个“WWW-Authenticate”头部字段使用[RFC2617]定义的框架,以下所示: challenge = "OAuth2" [ RWS 1#param ] param = scope / error / error-desc / error-uri / ( token "=" ( token / quoted-string ) ) scope = "scope" "=" <"> scope-v *( SP scope-v ) <"> scope-v = 1*quoted-char quoted-char = ALPHA / DIGIT / "!" / "#" / "$" / "%" / "&" / "'" / "(" / ")" / "*" / "+" / "-" / "." / "/" / ":" / "<" / "=" / ">" / "?" / "@" / "[" / "]" / "^" / "_" / "`" / "{" / "|" / "}" / "~" / "\" / "," / ";" error = "error" "=" quoted-string error-desc = "error_description" "=" quoted-string error-uri = "error_uri" = <"> URI-reference <"> “scope”属性是一个空格隔开的做用域值的列表,代表了为了访问受保护资源所须要访问令牌做用域。“scope”属性必定不能出现屡次。 若是对于受保护资源的请求包含一个访问令牌而且验证失败了,那么资源服务器应该包含“error”属性来向客户端提供为什么访问请求被拒绝的缘由。参数值在6.2.1中描述。另外,资源服务器可能包含“error_description”属性来提供一我的类可读的解释,或者包含“error-uri”属性用一个绝对URI来指定一个用于解释错误的人类可读的网页。“error”、“error_description”和“error-uri”属性必定不能出现屡次。 例如,对于一个缺乏验证的受保护资源请求的响应: HTTP/1.1 401 Unauthorized WWW-Authenticate: OAuth2 对于一个使用过时访问令牌尝试验证的受保护资源请求的响应: HTTP/1.1 401 Unauthorized WWW-Authenticate: OAuth2 error="invalid_token", error_description="The access token expired" 6.2.1 错误码 当一个请求失败时,资源服务器使用恰当的HTTP状态码(典型的如400、401或403)进行响应,而且在响应中包含下列错误码之一: invalid_request 请求缺乏某个必需参数,包含一个不支持的参数或参数值,参数重复,使用多种方式包含访问令牌,或者请求格式不正确。资源服务器应该使用HTTP 400(Bad Request)状态码进行响应。 invalid_token 提供的访问令牌是过时的、已撤销的、格式不正确的,或因为其它缘由是无效的。资源服务器应该使用HTTP 401(Unauthorized)状态码进行响应。客户端可能请求一个新的访问令牌并重试受保护资源请求。 insufficient_scope 请求须要比访问令牌所提供的权限更高的权限。资源服务器应该使用HTTP 403(Forbidden)状态码进行响应而且包含“scope”属性,带上访问该受保护资源必需的做用域。 [[增长扩展错误码的机制]] 若是请求中缺乏任何验证信息(即客户端没有意识到验证是必需的或尝试使用一个不支持的验证方法),那么资源服务器不该该包含一个错误码和其它错误信息。 例如: HTTP/1.1 401 Unauthorized WWW-Authenticate: OAuth2 7. 扩展 7.1 定义新的客户端证书类型 [[待定]] 7.2 定义新的Endpoint参数 但愿在终端用户受权endpoint和令牌endpoint上定义新的请求和响应参数的应用,应该使用下列两种方式之一:在参数注册表中注册(听从9.1节描述的流程),或使用“x_”参数名前缀。 使用“x_”参数名前缀的参数必须局限于那些不会被普遍应用的针对厂商特性的扩展,而且特定于受权服务器使用场景的实现细节。全部其它参数必须被注册,而且必定不能使用“x_”参数名前缀。 参数名必须听从param-name的ABNF,而且参数值语法必须被规范地定义(例如,使用ABNF,或者引用到现存参数的语法)。 param-name = 1*name-char name-char = "-" / "." / "_" / DIGIT / ALPHA 7.3 定义新的头部字段参数 但愿在OAuth “WWW-Authenticate”头部字段中定义新参数的应用必须在参数注册表中进行注册,听从9.1节描述的流程。 参数名必须听从param-name的ABNF而且不能以“x_”开头。参数值必须听从param-value的ABNF而且语法必须被规范地定义(例如,使用ABNF,或者引用到现存参数的语法)。 param-value = quoted-value | quoted-string 7.4 定义新的访问许可类型 断言访问许可类型容许受权服务器接受其它未规定的访问许可。但愿定义其它访问许可类型的应用可以经过利用新的或现存的断言类型和格式进行实现。 8. 安全考虑 [[待定]] 9. IANA事项 9.1 OAuth参数注册表 本文档设立参数注册表。 用于终端用户受权endpoint的请求、终端用户受权endpoint的响应、令牌endpoint的请求、令牌endpoint的响应或“WWW-Authenticate”头部字段的多余参数,在一个或多个“指派专家”(由IESG或他们的代理机构指定)的指导下进行注册,听从所需的规范(使用[RFC5226]的术语)。然而,为了容许在发布以前对值进行分配,“指派专家”们一旦认同这样的一个规范可以发布,可能就当即批准注册。 注册请求应该发送给[待定]@ietf.org邮件组进行评审和讨论,使用恰当的标题(如“Request for parameter: example”)。[[RFC-EDITOR注解:邮件组名称应该在与IESG和IANA磋商后肯定。建议名称:oauth-ext-review。]] 在14天以内,“指派专家”们会批准或拒绝注册请求,并将结果告知邮件组和IANA。拒绝的决定应该包含一个解释,而且,若是可行的话,应该包含如何进行修改的建议。在21天以上未肯定的注册请求会交由IESG处理(使用iesg@iesg.org邮件组)。 9.1.1 注册模板 Parameter name: 请求的名称(例如“example”)。 Parameter usage location: 参数可以被使用的位置。可能的位置包括:终端用户受权endpoint的请求、终端用户受权endpoint的响应、令牌endpoint的请求、令牌endpoint的响应或“WWW-Authenticate”头部字段。 Change controller: 对于标准轨道的RFC,写明“IETF”。对于其它规范,使用负责机构的名称。其它细节(例如,邮编地址,电子邮件地址,主页URI)也能够包含。 Specification document(s): 对规定参数的文档引用,可取的方式是包含一个可以获取到文档拷贝的URI。对于相关章节的标示也能够包含,但不是必需的。 Related information: 可选地,对于包含更多相关信息的额外文档的引述。 9.1.2 例子 下面是对于本规范定义的“scope”参数的参数注册请求: Parameter name: scope Parameter usage location: The end-user authorization endpoint request, the end-user authorization endpoint response, the token endpoint request, the token endpoint response, and the "WWW-Authenticate" header field. Change controller: IETF Specification document(s): [[ this document ]] Related information: None