認識 OAuth 2.0:一次了解各角色、各類型流程的差異

文/Mike Huang

OAuth 有分 1.0 及 2.0 版本,本篇內容皆是以 OAuth 2.0 為出發點做介紹。另外,本篇提及數個平台作為範例來說明綜觀的 OAuth 2.0 概念,實際的畫面與機制可能與該平台有所差異,若要獲得各平台最新與最詳細的設計,可以參考其官方文件。

OAuth 2.0 介紹

講到開發應用程式,身份驗證功能通常少不了,實作上有非常簡易的方法,也有利用更多技術,讓驗證流程更完善和安全。

陽春版驗證功能

最簡易的驗證機制(如下圖),是使用者在客戶端透過基本的帳號與密碼向後端伺服器驗證身份。伺服器會經過一連串的驗證流程,驗證成功後透過如 Session / Cookie 機制,在客戶端保存用戶登入的狀態資訊。

缺點:安全性與維護

陽春版的劣勢,是我們必須自己維護驗證的機制與穩定性,也必須隨時檢視使用的驗證和保存機制,是否符合當前普遍認為的安全性等。例如將密碼進行雜湊後再儲存與比對即是一個普遍的做法。

OAuth2.0 解決方案

我們在許多拜訪的網站想要登入時,時常能看到像下圖 Medium 登入跳窗,提供多種登入的方式。在不經意的點擊下,我們其實已經使用到 OAuth 的流程。

OAuth 是一個開發標準(Open Standard)用來處理有關「授權」(Authorization)相關的行為。

這個使用 OAuth 的流程白話來說:「我們允許並授權當前的應用程式(在這是指 Medium)有限度的取得我們在 Facebook、Google 或其他平台的相關資訊」——使用者身份驗證的工作基本上是委由選擇的平台完成,當驗證成功,且用戶同意,應用程式才得以前往取得所需要的資源。

Source: Medium Sign in Popup

白話文介紹流程

當使用者點擊任一其中一個平台作為登入方式後,就會進入 OAuth 的流程( OAuth Flow)當中——流程的最後,能讓應用程式被授權代使用者取得相關被保護的資源。

以下假設以點擊「Sign in with Google」做為例子,並在瀏覽器中進行:

  1. 瀏覽器將使用者導頁至 Google 身份驗證的頁面,並透過 Google 的服務進行身份驗證。
  2. 身份驗證成功後,使用者會被詢問是否同意讓應用程式取得特定的一些資料。舉例來說,應用程式可能會希望能取得使用者在 Google 的名稱、Email、大頭照等。
  3. 使用者同意後,瀏覽器將把使用者帶回應用程式當中;使用者也能選擇不同意,那這個流程就在此結束了。
  4. 此時,使用者已經同意,應用程式就能順利前往 Google 存放資料的對應地方,去取得所需要的相關資料。

OAuth 2.0 常見用詞

流程中的角色(Roles)

?‍? Resource Owner

能授予應用程式取得受保護資料的人——通常就是終端使用者(end-user)。你在 Google 或 Facebook 等平台上擁有許多的資料,你就是 Resource Owner,你有權同意或拒絕應用程式代你取得這些資訊做使用。

⌲ 延續 Medium 範例,你就是 Resouce Owner。

?‍? Client

通常指稱想要取得受保護資源的「應用程式」。應用程式必須獲得 Resource Owner 的同意,才能代表使用者去取得相對應的資源。

⌲ 延續 Medium 範例,Medium 就是這裡指稱的 Client。

? Authorization Server

驗證 Resource Owner 的身份,並且在獲得同意之後,發放「Access Token」給應用程式(Client)的伺服器。

⌲ 延續 Medium 範例,就是指 Google 用來驗證你的身份的伺服器,你會使用 Google 帳號與密碼進行身份驗證,並被詢問是否同意伺服器代表你取得你在 Google 中的資料。

?‍? Resource Server

存放使用者受保護資料的伺服器,應用程式(Client)會需要帶著「Access Token」透過其 API 去取得資料。Resource Server 需要保護資料免於被未授權的他人取得。

⌲ 延續 Medium 範例,就是指 Google 存放你相關資料的伺服器。

其他用詞

? Authorization Grant

在流程中,是用來證明使用者同意賦予應用程式一定程度的授權、同意應用程式去做某些事、取得一個範圍內的資源。

⌲ 延續 Medium 範例,就是用來證明我已經同意 Medium 代我向 Google 取得我在 Google 相關的資料做使用。

? Redirect URI(Callback URL)

Authorization Server 在驗證完使用者身份並獲得授權同意後,將會把使用者帶回應用程式中指定的路徑。

? Access Token

Access Token 是 Authorization Server 簽發的。應用程式最終能拿著這個 Token 向 Resource Server 取得需要的資源

? Scope

使用者的授權時常並非一翻兩瞪眼,如果單純只是「可以取得我的所有資料」與「不可以取得我的所有資料」,彈性就相對很低。

也因此通常 Authorization Server 會有個 scope 的清單,例如:可以取得使用者的名稱、可以編輯使用者的大頭貼、可以刪除我的某則貼文等不同權限。

所以當 OAuth 流程一啟動時,Client 能依照需求提供所需要的權限清單。 Authorization Server 也會依照這個清單,尋求使用者的同意(Consent)。

流程圖搭配各角色與專有名詞

Authorization Code Flow

? 流程度注意事項
此圖是一個綜觀的基本 OAuth2.0 流程圖,事實上有好幾種變形,但大部分概念都是類似的,所以可以透過這個流程去做變化。以上是其中一種類型,叫 Authorization Code Flow,接著會有更多詳細介紹。

一樣是使用者(Resource Owner)在應用程式中點擊了「Sign in with Google」做為例子,並在瀏覽器中進行:

  1. 瀏覽器將使用者導頁至 Authorization Server(以 Google 為例,就是 https://accounts.google.com/),並提供對方所需的資訊。常見的如:
    ? Client Id:應用程式(Client) 在 Authorization Server 的身份識別
    ? Redirect URI:告知當流程結束後,需要轉址的位置在哪
    ? Response Type:告知想取得哪種 Authorization Grant(稍後會說明)
    ? Scope:用來劃分應用程式能代使用者在 Google 取得一定範圍的資源
  2. Authorization Server 進行使用者身份驗證。
  3. 身份驗證成功後,依據第一步設定的「scope」,使用者會被詢問是否同意讓應用程式取得所劃分的資源。例如在 scope 中定義只讓應用程式取得使用者在 Google 的名稱、Email 通訊錄,在這個階段就會被明確詢問。
  4. 使用者同意後,就會依照第一步設定的「Redirect URI」將使用者導回應用程式的指定路徑中,並依照 Response Type 回傳 Authorization grant;使用者也能選擇不同意,Authorization Server 會回傳相關錯誤訊息。
  5. 擁有 Authorization grant 其實還不能直接向 Resource Server 取得資源。應用程式必須拿著它重新向 Authorization Server 換取 Access Token。 Authorization Server 在驗證 Authorization grant,以及應用程式身份後,才會正式核發 Access Token。注意:這個 Access Token 的權限受限於在第一步所劃定 scope 清單。
  6. 應用程式最終就在取得資源的請求中夾帶著 Access Token 向 Resource Server 取得所需的資源。但也因為第一步有透過 scope 劃分可取得哪些資源或做哪些事,所以應用程式除了能代使用者取得其在 Google 的名稱及 Email 通訊錄,不能嘗試取得使用者得大頭貼。
❗️ 為什麼需要多一個步驟去交換 Access Token 而不直接核發?
考量的是「安全性」問題。上圖中實線的箭頭,代表著這些步驟都是發生在前端(如瀏覽器中),大部分都是透過頁面跳轉去傳遞訊息。例如:Callback URI、scope、authorization grant grant等,多半透過 Query String 作為傳遞,任何人都有機會看到,安全性上就需要畫上個問號。然而,從取得 Access Token 步驟開始(圖中虛線),就是在後端運作。通常是透過 HTTP Post 請求,夾帶著 Authorization grant 及應用程式的身份資訊(例如由 Google / Facebook 等平台提供給應用程式專屬的 Client ID、Secret Key,並且存放在後端)給 Authorization Server 進行驗證。也因為 Secret Key 只存放在後端伺服器,而非暴露在前端程式碼當中,因此安全性上就會比較高。

更多流程的細節補充

? Client 設定

前面有提到「Google / Facebook 等平台會提供給應用程式專屬的 Client ID、Secret Key」等身份資訊,這其實是應用程式在建構功能時需要做的初期設定。

開發者在使用 OAuth 以前,需要先在各平台為應用程式創建 Client 的身份,假設應用程式規劃要提供「Google 登入」的選項,則需要先前往 Google API Console 創建身份。(詳情可以參考 ? 官方文件)最終能為應用程式取得一組如下圖的 Client ID 及 Client Secret。

Client Secret 是非常隱私的,理論上只有 Google 和你的應用程式知道,所以能拿來透過後端向 Authorization Server 驗證 Client 的身份,以做為交換 Access Token 的其中一環。

? Sign in with Google 的導向

「Sign in with Google」按鈕背後的連結長得類似像下面的連結,當使用者點下去,就會被導向這個 Authorization Server 的位址,上面需要帶入相關設定資訊。
(補充:前四個步驟最終是希望取得「Authorization Grant」,Authorization Grant 有不同類型。在這邊因為是以 Authorization Code Flow 這種取得 Access Token 的方式做為舉例,所以 response_type 的值為 code)

https://accounts.google.com/o/oauth2/v2/auth?
scope=profile&
response_type=code&
redirect_uri=https://mike.example.com/callback&
client_id=mike123

? 使用者身份驗證與授權

以 Google 為例,點擊「Sign in with Google」後就會被導向以下都入畫面,下方也同時顯示了應用程式希望你授權同意它代為取得的相關資源訊息。

? 同意或拒絕授權的 Callback

同意或拒絕授權後,會將使用者導向應用程式指定的 Callback URI,並依據結果在 query string 帶上相對應的資訊:

// 使用者拒絕的導向連結:將會拿到錯誤資訊
https://mike.example.com/callback?error=access_denied// 使用者同意授權的導向連結: 將拿到 Authorization grant
https://mike.example.com/callback?code=8888888213

? 交換 Access Token

通常會透過 HTTP Post 請求,向 Authorization Server 取得 Access Token,請求基本上會帶上剛拿到的 Authorization grant 以及用來驗證應用程式身份的相關資訊(Client ID、Client Secret 等):

POST /token HTTP/1.1
Host: oauth2.googleapis.com
Content-Type: application/x-www-form-urlencoded

code=8888888213&
client_id=mike123&
client_secret=mike_secret&
redirect_uri=https://mike.example.com/callback&
grant_type=authorization_code

Authorization Server 在驗證後,就會在回傳中核發 Access Token,並提供相關資訊:

{
"access_token": "1/fFAGRNJru1FTz70BzhT3Zg",
"expires_in": 3920,
"token_type": "Bearer"
}

? 拿著 Access Token 取得資源

最後應用程式就能拿著這個 Access Token 向 Resource owner 依照自己被授與的權限取得資源:

GET https://www.googleapis.com/drive/v2/files HTTP/1.1
Authorization: Bearer 1/fFAGRNJru1FTz70BzhT3Zg

OAuth2.0 四種授權類型流程

OAuth2.0 定義了四種應用程式取得 Access Token 的流程,又稱為「Grant Types」。文章上半部介紹了其中一種,而接下來將完整介紹不同的類性——要使用哪種流程,能依照應用程式的類型簡單劃分:

Authorization Code

這是最常見的類型,Server-side Application (Web server applications)最為適用——通常會由後端伺服器負責產生頁面(View)回傳給前端渲染。如此一來,大部分的邏輯處理程式碼,以及像應用程式的 Client Secret 等重要機密資訊,都能在伺服器端被保存,而非完全公開。

Authorization Code Flow

這種類型就是我們文章到目前為止介紹的流程:

  • 應用程式將使用者導向 Google 進行身份驗證和授權。導頁的 URL 中透過 Query string 提供應用程式的身份,以及需要請使用者授予權限等相關資訊。(特別補充:前面範例使用的 response_type=code 代表應用程式請求的是 Authorization Code 這種 Authoriation Grant)
  • Google 接著負責使用者身份驗證,並詢問使用者是否同意授權(Consent)。
  • 成功後,將依據 Redirect URI 將使用者導回應用程式指定路徑,並附上 Authoriation Grant——以當前類型的流程來說,就是回傳「Authorization Code」。
  • 應用程式能拿著 Authorization Code 向 Authorization Server 交換取得 Access Token。
  • 最終應用程式就能拿著 Access Token 向 Resource Server 取得資料。

Implicit

適合 Client-side applications 的類型——通常會是整個應用程式都在前端運行,依需求向後端 API 取得資料。例如單純的靜態網站或 Single Page Application(SPA) 都適用。

由於整個應用程式都在前端運行,所以會缺少「後端伺服器透過 Authorization Code Grant 交換 Access Token 」的步驟。取而代之的是請 Authorization Server 直接核發 Access Token。

Implicit Flow

Implicit Flow 流程:

  • 應用程式將使用者導向 Google 進行身份驗證和授權。導頁的 URL 中透過 Query string 提供應用程式的身份,以及需要請使用者授予權限的相關資訊。(補充:在這要帶上的 Response Type 為 token 代表應用程式請求的是 Access Token)
  • Google 接著負責使用者身份驗證,並詢問使用者是否同意授權(Consent)。
  • 成功後,將依據 Redirect URI 將使用者導回應用程式指定路徑,並附上 Authoriation Grant ——以當前類型的流程來說,就是回傳「Access Token」。
  • 最終應用程式就能拿著 Access Token 向 Resource Server 取得資料。特別留意:不像 Authorization Code Flow,這邊是由前端獲得與管理 Access Token,並帶著 Access Token 發出請求前往取得資源,因此在安全性上「相對脆弱」。

Resource Owner Password Credentials

此流程是由使用者提供帳號與密碼等資訊給應用程式,由應用程式直接向 Authorization Server 交換 Access Token,體驗上和以往的帳號密碼登入雷同。

帳號與密碼等機密資訊(credentials)可能會被應用程式儲存起來,作為往後交換 Access Token 使用。因此「必須是使用者高度信賴的應用程式」才適合使用,且唯有前兩種皆不可行時,才會考慮使用當前類型的流程。因此,適用的情境,可能像公司內部的系統。

Resource Owner Password Credentials Flow

Resource Owner Password credentials 流程:

  • 通常會透過表單或其他形式,讓使用者提供帳號與密碼的身份驗證資訊。
  • 應用程式在取得使用者的帳號與密碼後,會提供給 Authorization Server 進行身份驗證。
  • Authorization Server 進行身份驗證成功後,就會核發 Access Token。
  • 最終應用程式就能拿著 Access Token 向 Resource Server 取得資料。

Client Credentials

適合用在 machine-to-machine (M2M) applications——通常是由應用程式向 Authourization Server 請求取得 Access Token 以獲取「自己」的相關資源,而非使用者的資源。

這個流程已經跳脫使用者,因此,使用者身份驗證的流程將不再需要。取而代之的,是應用程式必須向 Authorization Server 提供驗證所需的自身資訊。

Client Credentials Flow

Client Credentials Flow 流程:

  • 應用程式透過提供其 Client ID 及 Client Secret Token 等其他作為驗證的資訊(client credentials)給 Authorization Server 進行身份驗證。
  • Authorization Server 驗證成功後,核發 Access Token 給應用程式。
  • 應用程式取得 Access Token 後,即能代表自己向 Resource Server 取得自己的相關資料。

結語

OAuth 2.0 的應用很廣,最大的好處和廣泛應用的,是能讓使用者能允許第三方應用程式,取得其在另一個平台的資料,而不需要提供驗證資訊給該第三方應用程式。

它不僅能運用在 Web App 上,也能運用在 Mobile App、Desktop App 等不同類型的應用程式與情境中,但背後的概念在大方向上基本上是相同的。

這次的研究是主要是從 Web App 的角度去研究使用方式和認識概念,但由於不同的情境、不同的平台在使用上還是有所差異,期待未來有機會接觸更多的面向和應用場景。

推薦影片

參考資源

An Introduction to OAuth 2

OAuth 2.0

OAuth 2.0 Authorization Framework

使用 OAuth 2.0 存取 Google API

本文由 Mike Huang 授權轉載,原文連結

瀏覽 20,746 次

覺得不錯的話就分享出去吧!

發佈留言

Back to top button