你有沒有發現,現在很多網站都有「用 Google 登入」或「用 Facebook 登入」的按鈕?點下去就能直接登入,不用再記一組新的帳號密碼,超方便對吧?
這個背後的機制就叫做 OAuth 2.0。
不管你以後想串 Google、Facebook、GitHub 還是其他服務,流程其實都差不多。搞懂這套邏輯,以後串接任何第三方登入都難不倒你!
OAuth 是什麼?
OAuth 是一種「規範」
OAuth 的全名是 Open Authorization,它是一套開放的授權規範。
什麼是規範?你可以把它想成是一份「大家說好的遊戲規則」。
Google、Facebook、GitHub 這些大公司都遵守這套規則,所以不管你串哪一家的登入,流程都長得差不多。
目前最常用的版本是 OAuth 2.0,基本上你現在看到的第三方登入都是用這個版本。
OAuth 幫你解決什麼問題?
以前如果你想讓 A 網站存取你在 B 網站的資料,你可能要把 B 的帳號密碼給 A,這超不安全的。
OAuth 的做法是:你直接去 B 網站登入,B 確認你同意後,給 A 一個「通行證」(token),A 就能用這個通行證去拿資料,完全不需要知道你的密碼。
第三方登入按鈕怎麼運作?
很多人以為「Facebook 登入」按鈕背後很複雜,其實它就只是一個超連結而已,跟你平常寫的 <a href="..."> 沒兩樣。
點下去之後,通常會發生兩件事之一:
- 跳出一個新視窗(比較常見)
- 直接換掉目前的頁面
OAuth 2.0 完整流程
讓我們一步步拆解整個登入流程。
先來看一張流程圖,有個整體概念:
sequenceDiagram
participant User as 使用者
participant App as A 網站
participant FB as Facebook
User->>App: 1. 點擊「Facebook 登入」按鈕
App->>FB: 2. 跳轉到 Facebook 登入頁面
FB->>User: 3. 顯示登入畫面,請求帳號密碼
User->>FB: 4. 輸入帳號密碼,同意授權
FB->>App: 5. 導回 A 網站,帶上 code 或 token
App->>FB: 6. 用 token 去請求使用者資料
FB->>App: 7. 回傳使用者資料(email、名字等)
App->>User: 8. 登入成功!步驟一:點擊登入按鈕
使用者在 A 網站上看到「Facebook 登入」按鈕,點下去之後,瀏覽器會跳轉到 Facebook 的登入頁面。
這個按鈕背後其實就是一個連結,網址大概長這樣:
https://oauth.facebook.com/authorize?redirect_uri=https://example.com/callback&scope=email,profile&response_type=token這串網址包含了幾個重要資訊:
- redirect_uri:告訴 Facebook 登入完要把使用者導回哪裡
- scope:告訴 Facebook 你想要哪些資料(例如 email、個人資料)
- response_type:告訴 Facebook 你要 token 還是 code
後面會詳細解釋每個參數。
步驟二:使用者在 Facebook 登入並授權
使用者被導到 Facebook 的頁面後,會看到兩件事:
- 登入表單:如果使用者還沒登入 Facebook,會先請他輸入帳號密碼
- 授權確認:Facebook 會顯示「XXX 應用程式想要存取你的 email 和基本資料,你同意嗎?」
這邊有個很重要的觀念:使用者的密碼是輸入在 Facebook 的網站上,A 網站完全拿不到這組密碼。這就是 OAuth 安全的核心設計。
使用者點下「同意」之後,Facebook 就知道:「好,這個使用者同意讓 XXX 網站存取他的 email 了。」
步驟三:Facebook 把使用者導回 A 網站
使用者同意授權後,Facebook 會把使用者導回你一開始指定的網址(就是 redirect_uri 那個參數)。
導回來的時候,網址後面會帶上一些重要資訊,例如:
https://example.com/callback?token=abc123xyz或是:
https://example.com/callback?code=def456uvw這個 token 或 code 就是 Facebook 給你的「通行證」,證明使用者已經同意授權了。至於 token 跟 code 有什麼差別,後面會詳細解釋。
步驟四:用 Token 去請求使用者資料
拿到 token 之後,A 網站就可以拿這個 token 去跟 Facebook 要資料了。
請求大概長這樣:
GET https://graph.facebook.com/me?access_token=abc123xyzFacebook 收到這個請求後,會檢查:
- 這個 token 是不是有效的?
- 這個 token 有沒有權限拿 email?
如果都沒問題,Facebook 就會回傳使用者的資料:
{
"id": "123456789",
"name": "王小明",
"email": "xiaoming@example.com"
}這樣就成功拿到使用者資料,可以讓使用者登入 A 網站了!
網址參數詳解
前面提到,點擊登入按鈕後會跳轉到一個網址,像這樣:
https://oauth.facebook.com/authorize?redirect_uri=https://example.com/callback&response_type=token&scope=email,profile這串網址看起來很長,其實就三個重點:
redirect_uri(導回網址)
redirect_uri=https://example.com/callback這個參數告訴 Facebook:「使用者登入完之後,請把他導回這個網址。」
你可以導回前端頁面,也可以導回後端 API,後面會詳細說明差別。
response_type(回傳類型)
response_type=token或
response_type=code這個參數決定 Facebook 要給你什麼東西:
| 類型 | 說明 |
|---|---|
| token | 直接給你 token,可以馬上用 |
| code | 先給你一個 code,你要再拿 code 去換 token |
Token 模式(比較簡單)
sequenceDiagram
participant App as A 網站
participant FB as Facebook
App->>FB: 1. 跳轉到 Facebook 登入
FB->>App: 2. 登入成功,直接回傳 token
App->>FB: 3. 用 token 請求使用者資料
FB->>App: 4. 回傳資料一步到位,拿到 token 就能直接用。
Code 模式(比較安全)
sequenceDiagram
participant App as A 網站
participant FB as Facebook
App->>FB: 1. 跳轉到 Facebook 登入
FB->>App: 2. 登入成功,回傳 code
App->>FB: 3. 用 code 換 token
FB->>App: 4. 回傳 token
App->>FB: 5. 用 token 請求使用者資料
FB->>App: 6. 回傳資料多了一個步驟,要先用 code 去跟 Facebook 換 token。
為什麼 Code 模式比較安全?因為 code 只能用一次,而且換 token 的過程是在後端進行的,token 不會經過瀏覽器。
早期大家都用 code 模式,後來因為 token 模式比較方便,現在比較多人用 token 模式。
scope(權限範圍)
scope=email,profile這個參數決定你想要跟使用者要哪些資料或權限:
| Scope | 可以拿到什麼 |
|---|---|
| 使用者的電子郵件 | |
| profile | 使用者的基本資料(名字、頭像等) |
| friends_list | 使用者的好友列表 |
| publish | 幫使用者發文的權限 |
當使用者登入時,Facebook 會顯示:「這個應用程式想要存取你的 email 和基本資料,你同意嗎?」
重要觀念
你只能拿到你在 scope 裡面寫的東西!
如果你只寫 scope=email,那就算你後來想要使用者的好友列表,也要不到。
為什麼要分成「授權」和「請求資料」兩個步驟?
你可能會想:Facebook 幹嘛這麼麻煩?使用者登入同意之後,直接把 email、名字這些資料帶回來不就好了,為什麼還要多一個步驟?
讓我們先想像一下「直接給資料」會長什麼樣子。
如果直接給資料會怎樣?
假設使用者授權後,Facebook 直接把資料帶在網址回傳:
https://example.com/callback?email=xiaoming@example.com&name=王小明&birthday=1990-01-01這樣做有幾個問題:
敏感資料直接暴露在網址上
這串網址會出現在:
- 瀏覽器的歷史紀錄
- Server log
- 可能還會被其他網站透過 Referer header 看到
使用者的 email、名字就這樣到處都看得到,超不安全。
給出去就收不回來
假設今天 Facebook 把使用者的 email 直接傳給了 A 網站,資料就在 A 網站的資料庫裡了。
過了一個月,使用者覺得「我不想讓 A 網站有我的資料了」,怎麼辦?沒辦法。資料已經在別人手上,使用者沒有任何方法可以把它「收回來」或「刪掉」。
但如果用 Token 機制,Facebook 只是給了 A 網站一張「通行證」。哪天使用者不想授權了,去 Facebook 設定裡把這張通行證撤銷掉,A 網站以後就再也拿不到新資料了。
無法即時取得最新資料
假設 Facebook 直接把使用者的名字「王小明」傳給 A 網站。
三個月後,使用者在 Facebook 上把名字改成「王大明」。但 A 網站手上的還是當初那份舊資料「王小明」,它不會自動更新。
如果 A 網站想要拿到最新的名字,使用者就得重新登入授權一次,讓 Facebook 再傳一次資料給它。
但如果用 Token 機制,A 網站隨時可以拿 Token 去跟 Facebook 問:「這個使用者現在叫什麼名字?」就能拿到最新的資料,不需要使用者重新授權。
所以 OAuth 設計了「Token 機制」
與其直接給資料,Facebook 選擇給網站一張「通行證」(Token):
https://example.com/callback?token=abc123網站拿到這張通行證之後,再用它去跟 Facebook 請求資料。
這樣設計對使用者的好處是:
網址上不會有敏感資料
網址上只有一串看不出意義的 token,不是使用者的 email 或名字。
Token 本身有保護機制
- Token 會過期:通常幾小時後就自動失效,就算外洩損害也有限
- Token 有權限限制:網站只能拿到使用者當初同意的資料(scope 決定的)
使用者可以主動撤銷授權
使用者如果改變心意,隨時可以去 Facebook 設定裡取消對 A 網站的授權。一旦撤銷,A 網站手上的 Token 就立刻失效,再也拿不到任何資料。
敏感資料可以走更安全的管道
網站拿到 token 之後,可以在後端伺服器用它去請求資料,這樣使用者的敏感資料就不會經過瀏覽器:
sequenceDiagram
participant Client as A 網站前端(瀏覽器)
participant Server as A 網站後端
participant FB as Facebook 伺服器
Client->>Server: 1. 把 token 傳給後端
Server->>FB: 2. 用 token 請求使用者資料
FB->>Server: 3. 回傳 email、名字等資料
Server->>Client: 4. 登入成功!
Note over Server,FB: 步驟 2、3 是後端對後端<br/>使用者完全看不到對比如果資料直接在網址上傳遞:
sequenceDiagram
participant Client as A 網站前端(瀏覽器)
participant FB as Facebook
FB->>Client: 直接把 email、名字帶在網址上
Note over Client: 敏感資料經過瀏覽器<br/>會被歷史紀錄、log 記錄用 Token 機制,敏感資料只在後端伺服器之間傳遞,使用者的瀏覽器只會看到一串無意義的 token。
網站可以隨時拿最新資料
只要 token 還有效,網站隨時可以再去請求一次,拿到使用者最新的資料,不需要使用者重新登入。
簡單總結
| 直接給資料 | 先給 Token 再請求資料 |
|---|---|
| 敏感資料直接在網址上 | 網址上只有 token |
| 給出去就收不回來 | 使用者可以撤銷、Token 會過期 |
| 拿到的是當下的資料快照 | 網站可以隨時請求最新資料 |
| 只能透過網址傳遞 | 可以走後端,更安全 |
所以這個「多一步」的設計,就是為了讓整個授權流程更安全、讓使用者對自己的資料有更多控制權。
經典面試題:前端接收 vs 後端接收
這是一個很常見的面試題:OAuth 的 redirect_uri 應該導到前端還是後端?
還記得前面提到的 redirect_uri 參數嗎?它決定了使用者登入完成後,Facebook 要把使用者導回哪裡。這個「哪裡」可以是前端頁面,也可以是後端 API。
兩種做法各有優缺點,讓我們來看看。
後端模式(推薦)
使用者登入完成後,Facebook 把使用者導到後端 API,由後端處理完再轉回前端。
sequenceDiagram
participant User as 使用者
participant Frontend as A 網站前端
participant Backend as A 網站後端
participant FB as Facebook
User->>Frontend: 1. 點擊「Facebook 登入」
Frontend->>FB: 2. 跳轉到 Facebook 登入頁面
FB->>User: 3. 請使用者登入並授權
User->>FB: 4. 同意授權
FB->>Backend: 5. 導到後端,帶上 token
Backend->>FB: 6. 用 token 請求使用者資料
FB->>Backend: 7. 回傳使用者資料
Backend->>Frontend: 8. 轉回前端,帶上登入狀態
Frontend->>User: 9. 登入成功!
Note over Backend,FB: 步驟 5、6、7 都在後端<br/>使用者完全看不到 token優點
- Token 不會暴露給前端:整個 token 的處理都在後端進行,使用者的瀏覽器完全看不到 token,大幅降低被竊取的風險
- 可以做更多驗證:後端可以設定白名單,只接受來自 Facebook 網域的請求,防止偽造
- 安全性最高:這是 OAuth 官方推薦的做法
缺點
- 流程比較複雜:需要多一個轉跳步驟(後端處理完再轉回前端)
- 需要後端資源:後端要額外開一個接收用的 API endpoint
前端模式
使用者登入完成後,Facebook 直接把使用者導回前端頁面。
sequenceDiagram
participant User as 使用者
participant Frontend as A 網站前端
participant Backend as A 網站後端
participant FB as Facebook
User->>Frontend: 1. 點擊「Facebook 登入」
Frontend->>FB: 2. 跳轉到 Facebook 登入頁面
FB->>User: 3. 請使用者登入並授權
User->>FB: 4. 同意授權
FB->>Frontend: 5. 導回前端,帶上 token
Frontend->>Backend: 6. 把 token 傳給後端
Backend->>FB: 7. 用 token 請求使用者資料
FB->>Backend: 8. 回傳使用者資料
Backend->>Frontend: 9. 回傳登入狀態
Frontend->>User: 10. 登入成功!
Note over Frontend: 步驟 5 token 會經過瀏覽器<br/>使用者可以在網址列看到優點
- 流程比較簡單:不需要額外的後端轉跳邏輯
- 前端可以獨立處理:如果是純前端應用(SPA),不需要依賴後端
缺點
- Token 會暴露在前端:使用者可以在瀏覽器的網址列、開發者工具看到 token
- 有安全風險:如果使用者的電腦被植入惡意程式,token 可能被竊取
- 儲存方式要小心:如果把 token 存到
localStorage,任何在同一個網域執行的 JavaScript 都能讀取到
如果一定要用前端模式
如果真的沒有後端資源,用前端模式也不是不行,但要注意:
- 不要把 token 存到 localStorage:容易被 XSS 攻擊竊取
- 建議存在記憶體(memory)裡:也就是 JavaScript 變數,頁面關掉就消失
- 或用 httpOnly cookie:讓 JavaScript 無法直接讀取
兩種模式對比
| 後端模式 | 前端模式 | |
|---|---|---|
| Token 經過瀏覽器 | ❌ 不會 | ✅ 會 |
| 安全性 | 高 | 較低 |
| 實作複雜度 | 較複雜 | 簡單 |
| 需要後端支援 | 需要 | 不一定 |
| 適合情境 | 大部分情況 | 純前端應用、快速原型 |
結論
如果有後端人力,強烈建議用後端模式!
這也是面試時的標準答案。因為安全性永遠是第一考量,而後端模式能最大程度保護 token 不被洩露。
如果真的沒有後端資源,用前端模式也可以,但要特別注意 token 的保存方式,避免被有心人士竊取。
總結:OAuth 2.0 流程複習
讓我們快速複習整個流程:
- 使用者點擊登入按鈕
- 按鈕就是一個連結,跳到第三方登入頁面
- 網址帶三個重要參數
redirect_uri:登入完要導回哪裡response_type:要 token 還是 codescope:要哪些權限
- 使用者在第三方網站登入
- 密碼只給第三方,A 網站拿不到
- 導回你指定的網址
- 帶著 token 或 code 回來
- 用 token 去要資料
- 如果是 code,要先換成 token
- 只能要 scope 裡面有寫的東西
- 決定前端接收還是後端接收
- 有後端就用後端(比較安全)
- 沒後端用前端也可以(要小心保管 token)
下一步
學會 OAuth 2.0 的觀念後,你可以試著實際串接看看:
- Google 登入:搜尋「Google OAuth login」
- Facebook 登入:搜尋「Facebook OAuth login」
- GitHub 登入:搜尋「GitHub OAuth login」
每個服務的網址和參數名稱可能略有不同,但核心觀念都一樣。搞懂這套邏輯,串接任何第三方登入都沒問題!
💡 小提醒:實際開發時,記得去各平台的開發者後台註冊你的應用程式,才能拿到 client_id 等必要資訊喔!