OAuth是現在比較主流的授權方法,是從過去的技術逐漸演化出來的,因為是逐漸演變,裡面蘊含的技術與知識同樣也會變得非常多,非常複雜,所以我們可以一步一步的來理解整體OAuth的架構。
今天我們專注在 OAuth2 最常見、最安全的授權流程:Authorization Code Flow with PKCE。這個流程是目前 Web、行動 App 與 SPA 登入的主流解法。
回想一下昨天的觀念:OAuth 讓「第三方應用(Client)」能在不拿到密碼的情況下,存取使用者資源。
但如果我們直接在瀏覽器回傳 Access Token,就會有兩個風險:
👉 解法:先拿一個「授權碼」(Authorization Code),再換 Access Token。
👉 進一步:加上 PKCE,避免授權碼被攔截後直接盜用。
先看最原始的版本(適合 Confidential Client,如後端 Web 應用):
使用者導向授權伺服器
https://accounts.google.com/o/oauth2/v2/auth?...
client_id
, redirect_uri
, scope
, state
, response_type=code
使用者登入並同意授權
授權伺服器回跳 redirect_uri,附帶 code
https://yourapp.com/callback?code=abc123&state=xyz
Client 拿授權碼換取 Access Token
Client 透過後端 POST 給 Authorization Server:
grant_type=authorization_code
code=abc123
redirect_uri=https://yourapp.com/callback
client_id=...
client_secret=...
拿到 Token
access_token
(+ refresh_token)。問題來了:
PKCE 就是解答,PKCE加了兩個參數:code_verifier
與 code_challenge
。
Client 先產生一個隨機字串:code_verifier
dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
計算 code_challenge
code_challenge = BASE64URL-ENCODE(SHA256(code_verifier))
導向授權伺服器(多帶 code_challenge)
https://accounts.google.com/o/oauth2/v2/auth?client_id=...&code_challenge=xyz&code_challenge_method=S256
使用者登入並同意
?code=abc123&state=...
Client 拿授權碼換取 Token(多帶 code_verifier)
POST 給 Authorization Server:
grant_type=authorization_code
code=abc123
redirect_uri=https://yourapp.com/callback
client_id=...
code_verifier=原始隨機字串
伺服器驗證
Authorization Server 會檢查:
code_verifier → SHA256 → ?= code_challenge
如果匹配,才會核發 Access Token。
即使攻擊者竊取了 code,也無法交換成 Token,因為他沒有 code_verifier
。
參數 | 用途 | 如果不用會怎樣 |
---|---|---|
state |
防 CSRF,驗證回跳是否對應原始請求 | 攻擊者可能偽造回跳,導致 Token 被送到錯誤地方 |
scope |
控制授權範圍 | 沒有限制會導致過度授權 |
redirect_uri |
回跳位址 | 如果開放過廣,攻擊者可用惡意網址截取 code |
code_verifier / code_challenge |
PKCE 保護授權碼 | 攻擊者可以直接用 code 換取 Token |
延續昨天的案例,你的應用 MangaCloud 想讓使用者用 Google 登入。
code_verifier
與 code_challenge
。openid email profile
。?code=abc123&state=xyz
。code_verifier
+ code
去換 Access Token 與 ID Token。今天我們深入了 Authorization Code Flow:
我相信看到這裡,大家應該會有一種混亂的感覺,雖然理解了一點PKCE的概念,但好像又不太了解,我自己在寫這篇的時候也是從一頭霧水到稍微了解,花上了一點時間,這個部分是一個很重要的觀念,但是在學習上比較困難。大家可以多花點時間慢慢地學習。
那我們今天的資訊就分享到這裡,大家明天見!