跳至主要内容

[Note] OAuth2.0 筆記

OAuth2 @ Google Developers

警告

本文章中之說明與圖片主要參考自簡單易懂的 OAuth 2.0 by Yu-Cheng Chuang。

速記

  • Authorization Server 根據使用者的 Client-ID 找到該使用者詢問是否允許 App 存取。
  • 使用者授權 App 後取得的代碼稱作 Grant CodeAuthorization Code
  • App 使用 Grant Code 向 Authorization Server 交換取得 Token,這個 Token 通常包含 access tokenrefresh token
  • 透過 access token App 可以存取使用者允許的資料。

OAuth2 中的角色

OAuth 指的是 Open Authorization,它是一個網頁或 App 可以存取另一個 App 使用者私人資料的方式,在 OAuth2.0 裡面的角色包含:

  • Resource Owner(User):資料擁有者,通常就是指「使用者」
  • Client(App):即 App,要存取 User 資料的程式
    • Redirect URI:當 User 本人親自確認後要返回結果到 Client
  • Authorization Server:總管一切授權事務
    • Authorization Endpoint:用來給 User 本人確認授權,通常是一個網頁,拿到的是 Grant Code/Authorization Code(授權狀)而不是 Token,當 User 答覆之後,會轉回 Client 的 Redirect URI。
    • Token Endpoint:用來給 Client 取得真正的 Token ,通常是 JSON API ,無網頁。
    • Redirection EndpointClient 用來接收資料用,用來從瀏覽器接受 Authorization Server 回傳的資料
  • Resource Server(API):即 API,Client 出示 Token 後即可進去取得資料,通常指的是 Google、Facebook、Apple 這類提供第三方登入的服務。

OAuth2 中的各種 token

  • Basic OAuth Token:根據 client ID 和 client secret,透過 Base64 Encode 後產生。
  • Access Token:用來打 Resource Server 的 API 要資料用的,可以設定存取權限範圍(Scope)和期限,並且可以撤銷。
  • Refresh Token:當 Access Token 過期時用來換發新的 Access Token 用的,Refresh Token 用過一次即失效。

OAuth2 的方式:Two-legged vs. Three-legged

OAuth 可以分成 two-legged 或 three-legged 兩種。Two-legged OAuth 是用在 server-to-server 之間的資料交換,並不能代表某個使用者;Three-legged OAuth 則是大家常用的第三方登入,

Two-legged OAuth

Two-legged OAuth 最主要是用在 server-to-server 之間的資料交換。

一般來說會分成兩個步驟:

STEP 1:使用 Basic Authorization 的方式取得 Access Token

  • 將 Resource Server 提供的 Client ID (Customer Key) 和 Customer Secret 組成字串 client_id:client_secret 後透過 Base64 組成編碼後的字串(encoded string)

PointCLickCare

imgur

// Go
func GenerateAuthBasicToken() string {
key := os.Getenv("PCC_CUSTOMER_KEY")
secret := os.Getenv("PCC_CUSTOMER_SECRET")
token := fmt.Sprintf("%v:%v", key, secret)
encoded := base64.StdEncoding.EncodeToString([]byte(token))
return encoded
}
// node
export const generateAuthBasicToken = (): string => {
const key = process.env.PCC_CUSTOMER_KEY;
const secret = process.env.PCC_CUSTOMER_SECRET;
const token = `${key}:${secret}`;
const encoded = Buffer.from(token, 'utf8').toString('base64');
return encoded;
};

把 encoded string 帶入 Header 中:

POST /auth/token HTTP/1.1
Host: connect.pointclickcare.com
Content-Type: application/x-www-form-urlencoded
authorization: Basic UmU5TFhuQmRQczRvMGo1aDFYaE53cDJPRWswbEdzeUs6eGJXRkF4VjIybnE5QnREdA==

grant_type=client_credentials

接著就會收到伺服器回傳的 access_token

{
"access_token": "3DSBNdh711xNVJWmdLR4dMLLSw4I:2",
"expires_in": "7199"
}

STEP 2:透過 Access Token 來和 resource server 交換資料

在 Request Header 中使用 Authorization: Bearer <accessToken> 來存取 resouce server 的資料

GET /api/public/preview1/orgs/66DA82A2-280A-4B3E-A8E7-0EE9CF25B96D/patients?facId=22 HTTP/1.1
Host: connect2.pointclickcare.com
Authorization: Bearer z7dl7559OgkBrVPrhk83ZqUkl1tJ:2

Three-legged OAuth

這是平常比較熟悉的第三方登入的方式。

流程

Imgur

State:用來防止 CSRF 攻擊

A. User 發出授權申請

  • User 點選發出授權申請後(例如,Login with Facebook),Client 會向 Authorization Server(例如,Facebook)發送請求:

Imgur

B. 問 Resource Owner

  • Authorization Server(Facebook)收到請求後會根據 Client ID 找 Client、確認 Redirect URI、確認想申請的 scope,都沒問題再詢問 Resource Owner(User) 要不要授權。

C. Client 收到 Grant Code/Authorization Code

  • 如果 Resource Owner(User) 給予授權,則轉回 Client(App) 時會附上 Grant Code/Authorization Code;若不允許,則轉回 Client(App) 時會附上錯誤訊息(通常會把資訊帶在回傳的 URL 上)。

使用者授權 App 後取得的代碼稱作 Grant CodeAuthorization Code

Imgur

Imgur

D. 拿 Grant Code 換 Token

  • Client(App) 再拿到 Grant Code 之後即可發 Request 到 Authorization Server 的Token EndpointToken
  • Authorization Server 收到後確認 Client Authentication 正確、找到該 Grand Code/Authorization Code、確認 Redirect URI 是一致的後,就回傳 Access Token

Imgur

E. 發 Token

Imgur

流程(Web App)

Imgur

Imgur

Imgur

錯誤處理

Imgur

拿到 Token 後如何打 API

  • 推薦:(in Header) Authorization: Bearer 2YotnFZF...
  • (in Body) &access_token=2YotnFZF...
    • 不可以是 multi-part
    • Content-Type: application/x-www-form-urlencoded
  • 不推薦:(in URL) ?access_token=2YotnFZF...

參考