OAuth 2.0 解決什麼問題
OAuth 2.0 很常被說成「第三方登入」,但這其實只說到它常見用途的一部分。OAuth 2.0 的核心不是登入,而是授權委託:使用者如何允許某個應用,在不交出自己帳號密碼的情況下,存取另一個服務上的受保護資源。
一句話回答:OAuth 2.0 是 RFC 6749 定義的授權框架,解決的是 delegated authorization:Resource Owner 授權 Client 存取 Resource Server 上的資源,Authorization Server 負責取得授權並簽發 Access Token;Client 之後用 Access Token 存取 API。OAuth 2.0 本身不是身份驗證協議,若要做登入與身份資訊,通常要使用建立在 OAuth 2.0 上的 OpenID Connect。
一、 必考觀念
1. OAuth 2.0 解決「不要把密碼交給第三方」
沒有 OAuth 以前,第三方應用如果想讀你的資料,可能會要求:
請輸入你的 Google 帳號密碼,我幫你讀取 Calendar。這非常危險:
- 第三方拿到你的完整密碼。
- 使用者無法限制第三方只能讀 Calendar。
- 撤銷存取很困難。
- 第三方可能保存密碼。
- 密碼外洩會影響整個帳號。
OAuth 2.0 的想法是:
使用者在原服務授權
-> 第三方拿到有限權限的 access token
-> 第三方不用知道使用者密碼2. OAuth 2.0 是授權,不是身份驗證
OAuth 2.0 的核心問題:
Client 能不能代表使用者存取某個資源?不是:
這個使用者是誰?如果要登入身份資訊,例如 user id、email、profile,通常要用 OpenID Connect。
簡化:
| 協議 | 核心 |
|---|---|
| OAuth 2.0 | 授權存取 API |
| OpenID Connect | 在 OAuth 2.0 上加入身份層 |
延伸讀:身份驗證、授權與身份識別的差異。
3. OAuth 2.0 是框架,不是單一流程
RFC 6749 定義的是 authorization framework。
它包含:
- 角色。
- Token。
- 授權流程。
- Grant types。
- Extension points。
但很多安全細節在後續 RFC 與 Best Current Practice 裡逐步補強,例如 PKCE、refresh token rotation、redirect URI 精確匹配等。
RFC 9700 是 OAuth 2.0 Security Best Current Practice,整理了現代 OAuth 實作應遵守的安全建議。
二、 四個角色
1. Resource Owner
資源擁有者,通常是使用者。
例如:
你擁有自己的 Google Calendar 資料。2. Client
想要存取資源的應用。
例如:
一個會幫你整理行程的第三方 App。Client 不是瀏覽器本身,而是那個應用。
3. Authorization Server
負責:
- 驗證使用者。
- 呈現授權頁。
- 取得使用者同意。
- 簽發 access token。
- 簽發 refresh token,視情況。
例如:
accounts.google.com4. Resource Server
真正保存 API 資源的服務。
例如:
Google Calendar APIClient 拿 access token 呼叫 Resource Server。
三、 OAuth 2.0 流程總覽
1. Authorization Code Flow
現代 Web / SPA / Mobile 常用 Authorization Code Flow,並搭配 PKCE。
2. 為什麼不用密碼?
Client 不接觸使用者在 Authorization Server 的密碼。
使用者只在 Authorization Server 登入:
Client -> redirect 使用者到 Authorization Server
使用者 -> 在 Authorization Server 登入與授權
Authorization Server -> 回 code 給 Client
Client -> 用 code 換 token這就是 delegated authorization。
3. Authorization Code 是一次性中介物
Authorization code:
- 短效。
- 單次使用。
- 不能直接呼叫 API。
- 用來換 access token。
- 應綁定 redirect URI、client、PKCE。
不要把 authorization code 當 access token。
四、 Access Token 與 Scope
1. Access Token 代表授權結果
Access Token 可以理解成:
Authorization Server 給 Client 的 API 存取憑證。Client 呼叫 API:
GET /calendar/events
Authorization: Bearer access_tokenResource Server 驗證 token 後,決定是否允許。
延伸讀:Access Token 與 Refresh Token。
2. Scope 限制存取範圍
Scope 表示授權範圍:
calendar.read
calendar.write
profile.read使用者授權時看到:
這個 App 想讀取你的 Calendar。Scope 的價值是最小權限:
只要讀取,就不要給寫入。3. Scope 不是你的系統全部權限模型
OAuth scope 通常用來限制 client 對 API 的存取範圍。
但系統內部仍可能有:
- RBAC。
- ABAC。
- 資料權限。
- 租戶權限。
- feature flag。
Scope 是授權的一層,不是所有權限問題的唯一答案。
五、 Redirect URI 與 State
1. Redirect URI 很重要
Authorization Server 授權後會導回 Client:
https://client.example.com/oauth/callback?code=...如果 redirect URI 驗證不嚴格,攻擊者可能把 code 導到自己的網站。
安全要求:
- 預先註冊 redirect URI。
- 精確匹配。
- 不使用開放重導向。
- 不接受任意 wildcard。
- HTTPS。
RFC 9700 也強調 redirect URI 驗證與防止 authorization code 被攔截的重要性。
2. State 防 CSRF
Client 發起授權時帶:
state=random-valueCallback 回來時檢查:
received state === stored state用途:
- 防止 OAuth login CSRF。
- 綁定使用者這次發起的 OAuth 流程。
- 可保存 redirect intent,但要避免塞敏感資料。
3. State 不等於 PKCE
| 機制 | 解決問題 |
|---|---|
| state | 防 CSRF、綁定這次授權流程 |
| PKCE | 防 authorization code 被攔截後換 token |
兩者都重要。
六、 PKCE
1. PKCE 解決什麼?
PKCE 是 Proof Key for Code Exchange。
它主要防止:
authorization code 被攔截
-> 攻擊者拿 code 去換 tokenClient 在開始流程時產生:
code_verifier
code_challenge = base64url(sha256(code_verifier))授權請求帶 code_challenge。
換 token 時提交 code_verifier。
Authorization Server 驗證兩者是否匹配。
2. 為什麼 SPA / Mobile 需要 PKCE?
SPA / Mobile 是 public client:
- 不能安全保存 client secret。
- 程式碼可能被使用者看到。
- redirect URI 可能被攔截。
所以不能靠 client secret 保護 code exchange。
PKCE 讓 code 即使被截獲,也沒有 code_verifier 就不能換 token。
3. 現代 OAuth 應預設使用 PKCE
RFC 9700 建議 authorization code grant 應使用 PKCE。對 public clients 更是必要。
下一篇第三方登入 / PKCE 專題會更深入展開。
七、 Grant Types
1. Authorization Code
最推薦的互動式授權流程。
現代實務:
Authorization Code + PKCE適合:
- Web app。
- SPA。
- Mobile app。
- 第三方登入基礎流程。
2. Client Credentials
用於 machine-to-machine。
service A -> service B沒有使用者參與。
適合:
- 後端服務存取 API。
- Batch job。
- Server-to-server integration。
3. Device Authorization Grant
適合輸入受限裝置:
- TV。
- CLI。
- IoT。
使用者在另一台裝置完成授權。
4. Resource Owner Password Credentials 不建議
ROPC 讓 Client 直接收使用者帳密:
Client 收 user password
-> 拿去換 token這違背 OAuth 最初想避免「第三方拿到使用者密碼」的目的。現代實務通常不建議使用。
5. Implicit Flow 已不建議
Implicit Flow 會直接從 front-channel 回 access token。
現代 SPA 應使用:
Authorization Code + PKCERFC 9700 也不建議使用 implicit grant。
八、 OAuth 和第三方登入的關係
1. 第三方登入通常是 OIDC
當你看到:
用 Google 登入真正用來拿身份資訊的通常是 OpenID Connect。
OAuth 2.0 給你 access token,讓你存取 API。
OIDC 會提供:
- id token。
- userinfo。
- subject。
- profile claims。
2. 只用 OAuth access token 不一定知道使用者是誰
OAuth access token 可以表示:
這個 Client 可以讀某些 API。但它不一定是給 Client 當登入身份資訊用。
如果 Client 想登入使用者,應使用 OIDC。
下一篇會專門寫 OpenID Connect 與 OAuth 的差異。
3. 第三方登入後仍要有本地帳號
你的系統通常還是要建立:
local user
external identity mapping
local session
local authorizationOAuth / OIDC 解決的是外部身份與授權流程,不會自動替你設計本地會員系統。
九、 常見錯誤
1. 把 OAuth 當登入協議
OAuth 2.0 本身是授權框架,不是身份驗證協議。
要做登入應使用 OIDC。
2. 不驗 state
不驗 state 會增加 login CSRF 與流程混淆風險。
3. Redirect URI 開太寬
例如:
https://client.example.com/*或允許任意 redirect。
這會讓 authorization code 洩漏。
4. SPA 使用 implicit flow
現代 SPA 應使用 Authorization Code + PKCE,不應再用 implicit flow。
5. 把 access token 當萬用身份資料
Access token 的 audience 可能是 Resource Server,不一定是 Client。Client 不應隨便 decode access token 當登入 profile。
6. Scope 設太大
不該只要求:
all
admin
full_access應該按功能拆 scope,遵守最小權限。
十、 追問題庫
Q1:OAuth 2.0 解決什麼問題?
OAuth 2.0 解決 delegated authorization:第三方應用如何在不取得使用者密碼的情況下,經使用者授權後,用 access token 存取 Resource Server 上的受保護資源。
Q2:OAuth 2.0 是登入協議嗎?
不是。OAuth 2.0 是授權框架。登入身份層通常由 OpenID Connect 提供。
Q3:OAuth 2.0 四個角色是什麼?
Resource Owner、Client、Authorization Server、Resource Server。
Q4:Scope 是什麼?
Scope 是 access token 的授權範圍,例如 read/write 權限。它限制 Client 能對 Resource Server 做什麼。
Q5:State 和 PKCE 差在哪?
State 防 CSRF 與綁定流程;PKCE 防 authorization code 被攔截後被攻擊者拿去換 token。
Q6:為什麼不建議 Implicit Flow?
因為 access token 直接經 front-channel 回到瀏覽器,暴露風險高。現代 SPA 應使用 Authorization Code + PKCE。
十一、 實作題
題目:設計 OAuth 授權請求
需求:
- Client 要存取使用者 Calendar。
- 使用 Authorization Code + PKCE。
- 要防 CSRF。
- 授權後回 callback。
建立授權 URL:
function createAuthorizationUrl() {
const state = randomString()
const codeVerifier = randomString()
const codeChallenge = sha256Base64Url(codeVerifier)
oauthStateStore.save({
state,
codeVerifier,
redirectAfterLogin: '/settings/integrations',
})
const params = new URLSearchParams({
response_type: 'code',
client_id: 'client_123',
redirect_uri: 'https://app.example.com/oauth/callback',
scope: 'calendar.read',
state,
code_challenge: codeChallenge,
code_challenge_method: 'S256',
})
return `https://auth.example.com/authorize?${params.toString()}`
}Callback:
async function handleCallback(query: CallbackQuery) {
const saved = oauthStateStore.get(query.state)
if (!saved) {
throw new InvalidStateError()
}
const tokenResponse = await oauthClient.exchangeCode({
code: query.code,
redirectUri: 'https://app.example.com/oauth/callback',
codeVerifier: saved.codeVerifier,
})
await integrationRepository.saveToken({
accessToken: tokenResponse.access_token,
refreshToken: tokenResponse.refresh_token,
scope: tokenResponse.scope,
})
}重點:
- state 必須驗。
- code_verifier 不進 URL。
- redirect_uri 要和註冊值一致。
- scope 只要求需要的權限。
十二、 資深視角
1. OAuth 是授權邊界設計
成熟回答要能說:
誰授權?
授權給誰?
可以存取什麼?
token 給誰用?
如何撤銷?
如何限制 scope?不是只說「跳到 Google 登入再 callback」。
2. OAuth 安全細節很多
至少要注意:
- redirect URI 精確匹配。
- state。
- PKCE。
- scope 最小化。
- access token audience。
- refresh token rotation。
- secret 管理。
- 不使用 implicit flow。
- 不使用 ROPC。
這些是現代 OAuth 實作的基本安全要求。
3. OAuth 不取代本地授權
OAuth provider 告訴你:
外部授權結果你的系統仍要處理:
- 本地使用者。
- 本地角色。
- 本地權限。
- 租戶。
- 資料範圍。
- audit log。
不要把外部 token 當成內部全部權限。
總結
| 問題 | 回答重點 |
|---|---|
| OAuth 解決什麼 | 第三方委託授權,不交出密碼 |
| 四個角色 | Resource Owner、Client、Authorization Server、Resource Server |
| Access Token | Client 用來存取 Resource Server |
| Scope | 限制 token 可做什麼 |
| Authorization Code | 短效中介物,用來換 token |
| State | 防 CSRF、綁定流程 |
| PKCE | 防 code 被攔截後換 token |
| OAuth vs OIDC | OAuth 授權,OIDC 提供身份登入層 |
| 現代建議 | Authorization Code + PKCE,不用 implicit / ROPC |
一句完整的面試回答可以是:
OAuth 2.0 解決的是委託授權問題:使用者不需要把自己在 Resource Server 的帳號密碼交給第三方 Client,而是在 Authorization Server 上登入並授權,Authorization Server 簽發 access token 給 Client,Client 再用 access token 存取 Resource Server 上被授權的資源。OAuth 2.0 有四個角色:Resource Owner、Client、Authorization Server、Resource Server。Scope 用來限制授權範圍,Access Token 代表授權結果。現代互動式流程通常使用 Authorization Code + PKCE,並搭配 state 防 CSRF、redirect URI 精確匹配、防止 code 攔截。OAuth 2.0 本身不是登入協議,如果要取得使用者身份資訊,應使用 OpenID Connect。