# OAuth 2.0 (The OAuth 2.0 Authorization Framework) 協議簡介
IETE 鎖定定義的公開標準[RFC6749](https://datatracker.ietf.org/doc/html/rfc6749)
## 如何獲取使用者授權
## 如何向授權伺服器請求 Access Token
## 角色定義

|角色|說明|
|-|-|
|Resource Owner|資源擁有者,通常都是指「使用者」。|
|Resource Server|資源伺服器,用來存放使用者受保護資源的伺服器。|
|Client|應用程式,泛指對資源擁有者的資源有興趣的服務。|
|Authorization Server|授權伺服器,專門用來處理授權的伺服器。|

## OAuth 2.0 的 4 種授權類型 (Grant Type)
* Authorization code grant 流程時序圖
* 這是常見也相較安全的授權類型。
* 
* 這個流程有兩個關鍵:
* 應用程式主要和使用者互動只有第 1 步,有另外兩個步驟是轉導行為,一個是第 2 步轉導去授權伺服器,另一個是第 5 步轉導回應用程式。這裡可以發現,應用程式是無法控制使用者授權行為,只能由使用者主動按「同意授權」,應用程式才能夠得到成功授權的結果。
* 使用者無法看到 Access Token 內容,因此攻擊者要偷取可用的 Token 是困難的。一般攻擊者可以透過植木馬或注入惡意程式碼到使用者電腦中,再讓瀏覽器執行程式把資料傳送給攻擊者。但使用者看不到 Access Token,攻擊的困難度就會提高。
因為 Authorization Code 授權流程設計上是完整且安全的,因此是目前 OAuth 2.0 主流的授權類型。
* Implicit grant 流程時序圖
* 正如其名,在授權流程中有部分的流程是被隱含完成的,主要是在取得 Token 的步驟時,省略了驗證應用程式身分的流程。這容易讓 Access Token 有被「非應用程式身分」的攻擊者偷走的風險。現已被 OAuth 2.0 Security BCP 文件 為不應該(SHOULD NOT)使用的流程,目前大多數的情境都有對應的解法,但只剩 SPA(Single-Page Application,協定裡的專有術語是稱為 Browser-Based Application)有可能還需要使用 Implicit 授權模式,其他基本上都應該採用 Authorization Code 授權模式。
* 
* 問題主要在第 5 步:Access Token 放在 URI 的 Fragment 中。
* 雖然 HTTP 協定有提到請求資源的時候,不應該把 Fragment 包含在請求資源的一部分,但假設瀏覽器或伺服器沒有按照著這個協定實作的話,就有機會被中間人攻擊;另一方面,即便瀏覽器跟伺服器都有照著規範實作,因為 Fragment 依然是網址的一部分,Javascript 還是有辦法解析並取得 Access Token 的,若被 XSS 攻擊,Access Token 就有被偷的風險。
* 因為存在這些風險,因此 Implicit 被定為「不應該」使用的流程。
* Resource owner password credentials grant 流程時序圖
* 簡稱為 ROPC。這個授權類型與 Authorization Code 和 Implicit 一樣,會經由使用者授權,但不一樣的是:在這個流程裡,使用者不會經過授權伺服器,而是應用程式直接向使用者要求授權伺服器的驗證資訊來完成授權。
* 
* 這個做法與最初提到的問題是類似的--應用程式會接收到使用者的帳號密碼,對使用者來說就會多一層風險。但使用帳密的方法是不同的,ROPC 是用帳密來交換 Access Token,後續存取資源就改用 Access Token,因此後續就不需要再儲存帳密,進而避免帳號密碼存明文的風險。
* 因為使用者的帳號密碼還是會需要經過應用程式,因此協定是建議這個授權類型僅用在應用程式是高度可信賴的時候,比方說應用程式是另一個子公司所開發的。
* 但是!事實上各種文章或是理論,都在說明 ROPC 授權類型存在非常多問題。
* Client credentials grant 流程時序圖
* 應用程式直接跟授權伺服器做驗證,不透過使用者授權。
* 
* 主要應用在「應用程式本身就是資源擁有者」的情境,因此 Access Token 只能管理應用程式本身能管理的資源。像 GitHub 的 Personal Access Token 就是類似這樣的應用,只是它代表的是帳號的使用者本人,而不是應用程式。
## 授權流程 - 以 Authorization Code Grant 為例
* 白名單: 確保`redirect_uri`可以正確導到正確的應用程式,避免黑客可以一直`try`其他的應用程式,
* client 在開始授權之前,需要先跟授權伺服器註冊 client 的相關資訊
|註冊資訊|說明|
|-|-|
|client identifier|client 的唯一識別碼|
|client authentication|client 驗證的方法,如[密碼](https://ithelp.ithome.com.tw/articles/10223365)或是[JWT](https://ithelp.ithome.com.tw/articles/10225934)等|
|client password|client 的密碼驗證方法,若授權伺服器有發密碼的話,則必須提供[HTTP basic authentication scheme](https://ithelp.ithome.com.tw/articles/10223122)|
1. (步驟一) client 透過 User Agent 發出授權請求 (authrization request) 到授權伺服器的授權端口,
* 請求帶有以下資訊:
|欄位名稱|必要參數|說明|
|-|-|-|
|response_type|REQUIRED|指的是回應類型為何,此範例為<font color='red'>code</font>|
|client_id|REQUIRED|client 預先註冊好的唯一識別碼|
|redirect_uri|OPTIONAL|client 預先註冊好的轉導頁面|
|scope|OPTIONAL|授權範圍|
|state|RECOMMENDED|亂數,可用來確保授權請求與授權回應為同一使用者|
* 參數使用<font color='red'>application/x-www-form-urlencoded</font>編碼後,把它作為 HTTP query 放到授權端口的後面,並產生 URI。接著讓 Client 使用 302 redirect 到此 URI。
* 補充
* 授權請求為`response_type: token`,回傳給 client 的時候
2. (步驟二) Client 拿到 code 之後,還不能當作通行證來做使用,需要再帶著`code`對授權伺服器提供的 token endpoint 發送 POST 請求。
3. (步驟三) 除此之外,還需要提供額外身分驗證資訊 - 指註冊所約定好的驗證方法。
|欄位名稱|必要參數|說明|
|-|-|-|
|grant_type|REQUIRED|協定規定為 authorization_code|
|code|REQUIRED|授權成功回應的 code|
|redirect_uri|REQUIRED|必須與授權請求 redirect_uri 相同|
4. (步驟四) 最後成功即可拿到 access token 資訊,以及 metadata
|欄位名稱|必要參數|說明|
|-|-|-|
|access_token|REQUIRED|授權服務發行的 token|
|token_type|REQUIRED|說明 access token 是何種型式|
|expires_in|RECOMMENDED|Token 多久後會過期|
|refresh_token|OPTIONAL|可用來重換新的 token|
|scope|OPTIONAL最終接受的授權範圍|
## [Token Revocation、Token Introspection](https://ithelp.ithome.com.tw/articles/10226911)
### [OAuth 2.0 - 4.1.3. Access Token Request](https://www.rfc-editor.org/rfc/rfc6749#section-4.1.3)
### [OAuth 2.0 - 4.1.4. Access Token Response](https://www.rfc-editor.org/rfc/rfc6749#section-4.1.4)
### [OAuth 2.0 - 5.2. Error Response](https://www.rfc-editor.org/rfc/rfc6749#section-5.2)
### 資料來源
[Miles](https://ithelp.ithome.com.tw/m/articles/10291817)
[授權流程](https://ithelp.ithome.com.tw/articles/10226271)
[Vue3 串接 Google OAuth 登入](https://ithelp.ithome.com.tw/articles/10304289)
### 延伸
#### [OpenID Connect](https://ithelp.ithome.com.tw/m/articles/10293020)
* 與`Oauth2.0`差異比較
|OAuth 2.0 的角色|OpenID Connect 相似的角色|OpenID Connect 說明|
|-|-|-|
|Resource Owner|End-User|最終使用者(簡稱使用者),OpenID Connect 協定指的是真實的使用者。而在 OAuth 2.0 授權的情境裡,有可能應用程式同時也是資源擁有者,這點略為不同。|
|Resource Server|UserInfo Endpoint|提供使用者資訊的端點,OpenID Connect 主要是處理身分驗證,因此這個端點是提供使用者相關的資訊為主。OAuth 2.0 就包山包海,不侷限在身分驗證的場景上。|
|Client|Relying Party(RP)|直譯是依賴方,但稱之應用程式(Application)不會有誤解,也比較好討論。基本上與 OAuth 2.0 相同。|
|Authorization Server|OpenID Provider(OP)|OpenID 服務提供者,提供 OpenID Connect 的服務,其實是指 Authorization Server 加上身分驗證功能的服務。|
##### 身分驗證請求與回應
* 身分驗證請求(Authentication Request)
* 是基於授權請求再擴充出來的規格,`OpenID Connect`定義了獨立的授權範圍`openid` ,以及多個與身分驗證相關的自定義欄位。
* 身分驗證回應(Authentication Response)
* 多了一個`ID Token`,內容是`JWT`,包含了使用者身分相關聲明(cliam),包括主體(subject)的唯一識別碼。
#### 定義並註冊回應模式
* 授權回應或是身分驗證回應,與`HTTP`回應(Response)是不同的。所以實務上,授權伺服器回應應用程式的方法,並不像`HTTP API`一樣有會有請求端點、方法或是回應狀態碼等。
* 此份協定定義了`Response Mode`作為回傳的方法,並使用新的參數`response_mode`指定。以下是定義的值,與實際的行為。
* 
#### 定義多個回應類型的方法
* 
#### 新增身分驗證相關的協定
* OpenID Connect 有額外定義一些身分驗證場景才會有的協定,如「從第三方啟動登入」這個協定就是授權場景沒有的;另外身分驗證相關的資訊其實是能夠定義得出來的,也就是 ID Token 的內容,如主體的唯一識別碼、身分驗證時間、Token 的發放與過期時間等;使用者的個人資訊也有額外定義聲明(Claims),如姓名、Email、生日等。
#### 新增身分驗證狀態管理
* 登入是使用者經過身分驗證完成,並保存已驗證狀態的一個過程,同時還會有另一個相對的行為是登出,是將已驗證狀態清除的過程。OpenID Connect 根據這個需求設計了狀態管理機制(Session Managerment)以及操作的方法。
* 另一個 Web 開發者所熟知的狀態管理機制--RFC 6265 - HTTP State Management Mechanism,也就是 Cookie 機制。Cookie 機制與 OpenID Connect 所定義的狀態管理不同的地方在於,Cookie 機制是依賴於網域,因此會有跨網域無法驗證的問題;而 OpenID Conect 要解決的問題就是跨網域的身分驗證和狀態管理,所以這也是兩種機制的主要差別。