[Note] OAuth2.0 筆記
OAuth2 @ Google Developers
警告
本文章中之說明與圖片主要參考自簡單易懂的 OAuth 2.0 by Yu-Cheng Chuang。
速記
- Authorization Server 根據使用者的 Client-ID 找到該使用者詢問是否允許 App 存取。
- 使用者授權 App 後取得的代碼稱作
Grant Code
或Authorization Code
。 - App 使用
Grant Code
向 Authorization Server 交換取得Token
,這個 Token 通常包含access token
和refresh token
。 - 透過
access token
App 可以存取使用者允許的資料。
OAuth2 中的角色
OAuth 指的是 Open Authorization,它是一個網頁或 App 可以存取另一個 App 使用者私人資料的方式,在 OAuth2.0 裡面的角色包含:
- Resource Owner(User):資料擁有者,通常就是指「使用者」
- Client(App):即
App
,要存取User
資料的程式- Redirect URI:當
User
本人親自確認後要返回結果到Client
- Redirect URI:當
- Authorization Server:總管一切授權事務
- Authorization Endpoint:用來給
User
本人確認授權,通常是一個網頁,拿到的是Grant Code/Authorization Code
(授權狀)而不是Token
,當 User 答覆之後,會轉回Client
的 Redirect URI。 - Token Endpoint:用來給
Client
取得真正的 Token ,通常是 JSON API ,無網頁。 - Redirection Endpoint:
Client
用來接收資料用,用來從瀏覽器接受 Authorization Server 回傳的資料
- Authorization Endpoint:用來給
- 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)
// 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
這是平常比較熟悉的第三方登入的方式。
流程
State
:用來防止 CSRF 攻擊
A. User 發出授權申請
- User 點選發出授權申請後(例如,Login with Facebook),Client 會向 Authorization Server(例如,Facebook)發送請求:
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 Code
或Authorization Code
D. 拿 Grant Code 換 Token
Client(App)
再拿到Grant Code
之後即可發 Request 到 Authorization Server 的Token Endpoint
換Token
- Authorization Server 收到後確認 Client Authentication 正確、找到該
Grand Code/Authorization Code
、確認Redirect URI
是一致的後,就回傳Access Token
E. 發 Token
流程(Web App)
錯誤處理
拿到 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...
參考
- OAuth 2.0 的一個簡單解釋 @ 阮一峰的網絡日誌
- OAuth 2.0 的四種方式 @ 阮一峰的網絡日誌
- 簡單易懂的 OAuth 2.0 by Yu-Cheng Chuang @ Speakerdeck
- How to dance the OAuth: a step-by-step lesson @ freeCodeCamp
- Using OAuth 2.0 to Access Google APIs @ Google Developers