The OAuth 2.0 Authorization Framework
OAuth 2.0授權架構支援第三方支援通路有限的HTTP服務,通過在資源所有者和HTTP服務之間進行一個準許互動來代表資源者去通路這些資源,或者通過允許第三方應用程式以自己的名義擷取通路權限。
為了友善了解,可以想象OAuth2.0就是在使用者資源和第三方應用之間的一個中間層,它把資源和第三方應用隔開,使得第三方應用無法直接通路資源,進而起到保護資源的作用。
為了通路這種受保護的資源,第三方應用(用戶端)在通路的時候需要提供憑證。即,需要告訴OAuth2.0你是誰你要做什麼。
你可以将使用者名和密碼告訴第三方應用,讓第三方應用直接以你的名義去通路,也可以授權第三方應用去通路。
可以聯想一下微信公衆平台開發,在微信公衆平台開發過程中當我們通路某個頁面,頁面可能彈出一個提示框應用需要擷取我們的個人資訊問是否允許,點确認其實就是授權第三方應用擷取我們在微信公衆平台的個人資訊。這裡微信網頁授權就是使用的OAuth2.0。

1. Introduction
在傳統的client-server認證模型中,用戶端通過提供資源所有者的憑證來請求伺服器通路一個受限制的資源(受保護的資源)。為了讓第三方應用可以通路這些受限制的資源,資源所有者共享他的憑證給第三方應用。
1.1. Roles
OAuth定義了四種角色:
- resource owner(資源所有者)
- resource server(資源伺服器)
- client(用戶端):代表資源所有者并且經過所有者授權去通路受保護的資源的應用程式
- authorization server(授權伺服器):在成功驗證資源所有者并獲得授權後向用戶端發出通路令牌
1.2. Protocol Flow
抽象的OAuth2.0流程如圖所示:
- (A) 用戶端向資源所有者請求其授權
- (B) 用戶端收到資源所有者的授權許可,這個授權許可是一個代表資源所有者授權的憑據
- (C) 用戶端向授權伺服器請求通路令牌,并出示授權許可
- (D) 授權伺服器對用戶端身份進行認證,并校驗授權許可,如果都是有效的,則發放通路令牌
- (E) 用戶端向資源伺服器請求受保護的資源,并出示通路令牌
- (F) 資源伺服器校驗通路令牌,如果令牌有效,則提供服務
1.3. Authorization Grant
一個授權許可是一個憑據,它代表資源所有者對通路受保護資源的一個授權,是用戶端用來擷取通路令牌的。
授權類型有四種:authorization code, implicit, resource owner password credentials, and client credentials
1.3.1. Authorization Code
授權碼是授權伺服器用來擷取并作為用戶端和資源所有者之間的中介。代替直接向資源所有者請求授權,用戶端定向資源所有者到一個授權伺服器,授權伺服器反過來指導資源所有者将授權碼傳回給用戶端。在将授權碼傳回給用戶端之前,授權伺服器對資源所有者進行身份驗證并獲得授權。因為資源所有者隻對授權伺服器進行身份驗證,是以資源所有者的憑據永遠不會與客戶機共享。
1.3.2. Implicit
隐式授權是為了兼顧到在浏覽器中用諸如JavaScript的腳本語言實作的用戶端而優化的簡化授權代碼流程。在隐式授權流程中,不是發給用戶端一個授權碼,而是直接發給用戶端一個通路令牌,而且不會對用戶端進行認證。隐式授權提高了一些用戶端(比如基于浏覽器實作的用戶端)的響應能力和效率,因為它減少了獲得通路令牌所需的往返次數。
1.3.3. Resource Owner Password Credentials
資源所有者的密碼憑據(比如,使用者名和密碼)可以直接作為授權許可來擷取通路令牌。這個憑據隻應該用在高度信任的資源所有者和用戶端之間(比如,用戶端是系統的一部分,或者特許的應用),并且其它授權模式不可用的時候。
1.3.4. Client Credentials
用戶端憑據通常用作授權許可
1.3.5. Access Token
通路令牌是用來通路受保護的資源的憑據。一個通路令牌是一個字元串,它代表發給用戶端的授權。令牌代表資源所有者授予的對特定範圍和通路的時間(PS:令牌是有範圍和有效期的),并由資源伺服器和授權伺服器強制執行。通路令牌可以有不同的格式、結構和使用方法。
1.3.6. Refresh Token
Refresh Token是用于擷取Access Token的憑據。重新整理令牌是授權伺服器發給用戶端的,用于在目前通路令牌已經失效或者過期的時候擷取新的通路令牌。重新整理令牌隻用于授權伺服器,并且從來不會發給資源所有者。
重新整理的流程如圖所示:
- (A) 用戶端請求擷取通路令牌,并向授權伺服器提供授權許可
- (B) 授權伺服器對用戶端身份進行認證,并校驗授權許可,如果校驗通過,則發放通路令牌和重新整理令牌
- (C) 用戶端通路受保護的資源,并向資源伺服器提供通路令牌
- (D) 資源伺服器校驗通路令牌,如果校驗通過,則提供服務
- (E) 重複(C)和(D)直到通路令牌過期。如果用戶端直到通路令牌已經過期,則跳至(G),否則不能繼續通路受保護的資源
- (F) 自從通路令牌失效以後,資源伺服器傳回一個無效的令牌錯誤
- (G) 用戶端請求擷取一個新的通路令牌,并提供重新整理令牌
- (H) 授權伺服器對用戶端進行身份認證并校驗重新整理令牌,如果校驗通過,則發放新的通路令牌(并且,可選的發放新的重新整理令牌)
2. Client Registration
在使用該協定之前,用戶端向授權伺服器注冊。
2.1. Client Types
OAuth定義了兩種用戶端類型:
- confidential:能夠維護其憑證的機密性的用戶端
- public:不能維護其憑證的機密性的用戶端
2.2. Client Password
擁有用戶端密碼的用戶端可以使用HTTP Basic向伺服器進行認證,當然前提是授權伺服器支援HTTP Basic認證。
例如:Authorization: Basic czZCaGRSa3F0Mzo3RmpmcDBaQnIxS3REUmJuZlZkbUl3
二者選其一的,授權伺服器可能支援在請求體中用下列參數包含用戶端憑據:
- client_id:必須的,在授權伺服器中注冊過的用戶端辨別符。
- client_secret:必須的,用戶端秘鑰。如果秘鑰是空字元串的話可以省略該參數。
用這兩個參數将用戶端憑據包含在請求體中這種方式不推薦,并且應該限制用戶端不能直接用HTTP Basic認證方案。
3. Protocol Endpoints
授權處理用兩個授權伺服器端點:
- Authorization endpoint:用于用戶端從資源所有者那裡擷取授權
- Token endpoint:用于用戶端用授權許可互動通路令牌
還有一個端點
- Redirection endpoint:用于資源伺服器通過資源所有者使用者代理将包含授權憑據的響應傳回給用戶端
3.1. Authorization Endpoint
授權端點用于和資源所有者互動并擷取一個授權許可的。授權伺服器必須首先校驗資源所有者的身份。
3.1.1. Response Type
用戶端用以下參數通知授權伺服器自己渴望的授權類型:
- response_type:必須的。為了請求一個授權碼這個值必須是"code",為了請求一個通路令牌這個值必須是"token"
3.1.2. Redirection Endpoint
在完成和資源所有者的互動以後,授權伺服器直接将資源所有者的user-agent傳回給用戶端。授權伺服器重定向到這個user-agent
3.2. Access Token Scope
授權和令牌端點允許用戶端使用“scope”請求參數指定通路請求的範圍。反過來,授權伺服器使用“scope”響應參數通知客戶機它所發放的通路令牌的範圍。
4. Obtaining Authorization
為了獲得一個通路令牌,用戶端需要先從資源所有者那裡獲得授權。授權是以授權許可的形式來表示的。
OAuth定義了四種授權類型:
- authorization code
- implicit
- resource owner password credentials
- client credentials
4.1. Authorization Code Grant
授權碼流程如圖所示:
- (A) 用戶端通過将資源所有者的使用者代理指向授權端點來啟動這個流程。用戶端包含它的用戶端辨別符,請求範圍,本地狀态,和重定向URI,在通路被允許(或者拒絕)後授權伺服器立即将使用者代理傳回給重定向URI。
- (B) 授權伺服器驗證資源所有者(通過使用者代理),并确定資源所有者是否授予或拒絕用戶端的通路請求。
- (C) 假設資源所有者授權通路,那麼授權伺服器用之前提供的重定向URI(在請求中或在用戶端時提供的)将使用者代理重定向回用戶端。重定向URI包括授權碼和前面用戶端提供的任意本地狀态。
- (D) 用戶端用上一步接收到的授權碼從授權伺服器的令牌端點那裡請求擷取一個通路令牌。
- (E) 授權伺服器對用戶端進行認證,校驗授權碼,并確定這個重定向URI和第三步(C)中那個URI比對。如果校驗通過,則發放通路令牌,以及可選的重新整理令牌。
4.1.1. Authorization Request
用戶端通過使用“application/x-www-form- urlencoding”格式向授權端點URI的查詢元件添加以下參數來構造請求URI
- response_type:必須的。值必須是"code"。
- client_id:必須的。用戶端辨別符。
- redirect_uri:可選的。
- scope:可選的。請求通路的範圍。
- state:推薦的。一個不透明的值用于維護請求和回調之間的狀态。授權伺服器在将使用者代理重定向會用戶端的時候會帶上該參數。
例如:
GET /authorize?response_type=code&client_id=s6BhdRkqt3&state=xyz&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1
Host: server.example.com
4.1.2. Authorization Response
如果資源所有者授權通路請求,授權伺服器發出授權代碼并通過使用“application/x-www-form- urlencoding”格式向重定向URI的查詢元件添加以下參數,将其給用戶端。
- code:必須的。授權伺服器生成的授權碼。授權代碼必須在釋出後不久過期,以減少洩漏的風險。建議最大授權代碼生命期為10分鐘。用戶端不得多次使用授權代碼。如果授權代碼不止一次使用,授權伺服器必須拒絕請求,并在可能的情況下撤銷先前基于該授權代碼釋出的所有令牌。授權代碼是綁定到用戶端辨別符和重定向URI上的。
- state:如果之前用戶端授權請求中帶的有"state"參數,則響應的時候也會帶上該參數。
HTTP/1.1 302 Found
Location: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA&state=xyz
4.1.3.1. Error Response
- error:取值如下error_description:可選的
- invalid_request
- unauthorized_client
- access_denied
- unsupported_response_type
- invalid_scope
- server_error
- temporarily_unavailable
- error_description
- error_uri:可選的
4.1.3. Access Token Request
用戶端通過使用“application/ www-form-urlencoding”格式發送以下參數向令牌端點送出請求
- grant_type:必須的。值必須是"authorization_code"。
- code:必須的。值是從授權伺服器那裡接收的授權碼。
- redirect_uri:如果在授權請求的時候包含"redirect_uri"參數,那麼這裡也需要包含"redirect_uri"參數。而且,這兩處的"redirect_uri"必須完全相同。
- client_id:如果用戶端不需要認證,那麼必須帶的該參數。
POST /token HTTP/1.1
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb
4.1.4. Access Token Response
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"example",
"expires_in":3600,
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
"example_parameter":"example_value"
}
4.2. Implicit Grant
隐式授權用于擷取通路令牌(它不支援重新整理令牌),它針對已知的操作特定重定向URI的公共用戶端進行了優化。這些用戶端通常在浏覽器中使用腳本語言(如JavaScript)實作。
因為它是基于重定向的流程,是以用戶端必須有能力和資源所有者的使用者代理(典型地,是一個Web浏覽器)進行互動,同時必須有能力接收來自授權伺服器的重定向請求。
隐士授權類型不包含用戶端身份驗證,它依賴于資源所有者的存在和重定向URI的注冊。由于通路令牌被編碼到重定向URI中,是以它可能暴露給資源所有者以及同一台裝置上的其它應用。
隐式授權流程如圖所示:
- (A) 用戶端引導資源所有者的user-agent到授權端點。用戶端攜帶它的用戶端辨別,請求scope,本地state和一個重定向URI。
- (B) 授權伺服器對資源所有者(通過user-agent)進行身份認證,并建立連接配接是否資源所有者允許或拒絕用戶端的通路請求。
- (C) 假設資源所有者允許通路,那麼授權伺服器通過重定向URI将user-agent傳回用戶端。
- (D) user-agent遵從重定向指令
- (E) web-hosted用戶端資源傳回一個web頁面(典型的,内嵌腳本的HTML文檔),并從片段中提取通路令牌。
- (F) user-agent執行web-hosted用戶端提供的腳本,提取通路令牌
- (G) user-agent将通路令牌傳給用戶端
4.2.1. Authorization Request
- response_type:必須的。值必須是"token"。
- client_id:必須的。
- scope:可選的。
4.3. Resource Owner Password Credentials Grant
資源所有者密碼憑證授予類型适用于資源所有者與用戶端(如裝置作業系統或高度特權應用程式)存在信任關系的情況。授權伺服器在啟用這種授予類型時應該特别小心,并且隻在其他授權流程不可行的時候才允許使用。
這種授權類型适合于有能力維護資源所有者憑證(使用者名和密碼,典型地,用一個互動式的表單)的用戶端。
資源所有者密碼憑證流程如圖:
- (A) 資源所有者提供他的使用者名和密碼給用戶端
- (B) 用戶端攜帶從資源所有者那裡收到的憑證去授權伺服器的令牌端點那裡請求擷取通路令牌
- (C) 授權伺服器對用戶端進行身份認證,并校驗資源所有者的憑證,如果都校驗通過,則發放通路令牌
4.3.1. Access Token Request
用戶端通過在HTTP請求體中添加"application/x-www-form-urlencoded"格式的參數來向令牌端點請求。
- grant_type :必須的。而且值必須是"password"。
- username :必須的。資源所有者的使用者名。
- password :必須的。資源所有者的密碼。
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=password&username=johndoe&password=A3ddj3w
4.3.2. Access Token Response
4.4. Client Credentials Grant
用戶端用它自己的客戶單憑證去請求擷取通路令牌
用戶端憑證授權流程如圖所示:
- (A) 用戶端用授權伺服器的認證,并請求擷取通路令牌
- (B) 授權伺服器驗證用戶端身份,如果嚴重通過,則發放令牌
4.4.1. Access Token Request
- grant_type:必須的。值必須是"client_credentials"。
grant_type=client_credentials
4.4.2. Access Token Response
HTTP/1.1 200 OK
5. Issuing an Access Token
5.1. Successful Response
授權伺服器發放令牌
- access_token:必須的。
- token_type:必須的。比如:"bearer","mac"等等
- expires_in:推薦的。
- refresh_token:可選的。
media type是application/json,參數被序列化成JSON對象。
授權伺服器必須包含"Cache-Control"HTTP頭,并且值必須是"no-store"。
6. Refreshing an Access Token
請求參數
- grant_type:必須的。值必須是"refresh_token"。
- refresh_token:必須的。
grant_type=refresh_token&refresh_token=tGzv3JOkF0XG5Qx2TlKWIA
參考
https://tools.ietf.org/html/rfc6749
https://oauth.net/2/
https://aaronparecki.com/oauth-2-simplified/
https://www.oauth.com/oauth2-servers/access-tokens/password-grant/
https://www.oauth.com/oauth2-servers/access-tokens/authorization-code-request/
https://www.oauth.com/oauth2-servers/access-tokens/client-credentials/
https://www.oauth.com/oauth2-servers/device-flow/token-request/
https://www.oauth.com/oauth2-servers/access-tokens/refreshing-access-tokens/
https://www.oauth.com/oauth2-servers/token-introspection-endpoint/
https://developer.okta.com/blog/2018/05/24/what-is-the-oauth2-implicit-grant-type
https://www.oauth.com/