Skip to content

Instantly share code, notes, and snippets.

@ywwwtseng
Created April 19, 2025 17:02
Show Gist options
  • Save ywwwtseng/9a22273c1652286e6ec0f9ae84b2633a to your computer and use it in GitHub Desktop.
Save ywwwtseng/9a22273c1652286e6ec0f9ae84b2633a to your computer and use it in GitHub Desktop.

OIDC、OAuth 2.0、SSO、JWT、Token、Session、Cookie 全面整理


🔐 一、OAuth 2.0(AUTH 2.0)

OAuth 2.0 是一種授權(Authorization)框架,不是用來驗證身份的(不是 Authentication),而是允許第三方應用程式代表用戶訪問資源,但不暴露用戶密碼。

📌 比喻:

你去銀行(資源伺服器)開戶,銀行要你提供身份證(Access Token),但不是你的鑰匙(密碼),這個身份證是政府(身份提供者)發給你的。


👤 二、OIDC(OpenID Connect)

OIDC 是建立在 OAuth 2.0 之上的一個身份驗證(Authentication)層。

  • OAuth 2.0 ➜ 確認你有「權限」使用某些資源
  • OIDC ➜ 確認你是「誰」

✅ OIDC 會傳回:

  • ID Token(用 JWT 格式):包含用戶的資訊(例如名稱、email)
  • Access Token:給應用程式使用,用來存取 API

🔁 三、SSO(Single Sign-On)單一登入

SSO 是一種讓你只需登入一次,就能訪問多個應用的機制。

🧩 舉例:

你登入 Google 帳號後,不需要重新登入 Gmail、YouTube、Google Drive,這就是 SSO。

🔧 SSO 通常就是靠 OAuth 2.0 + OIDC + JWT 完成的

✅ 實作原則:

  • 各系統(A、B)共用同一個身份提供者(如 Auth0, Google, Okta)
  • 登入一次後,身份提供者回傳 Token
  • 各應用以此 Token 進行驗證與登入

❓ A, B 系統的 Token 會不一樣嗎?

  • 如果 A、B 都使用同一個 Identity Provider:
    • Access Token 通常不同,因為每個應用的 audience 不一樣
    • ID Token 可以一樣,如果是針對相同使用者簽發

✅ 是否要自行產生 Token?

  • 通常身份提供者已回傳 JWT Token(ID Token、Access Token)
  • 若服務端需要控制細節(如權限細分),可以自行產生內部用 Token(如 Session Token)

🧾 四、JWT(JSON Web Token)

JWT 是一種 Token 格式,裡面可以裝使用者的資料,用於識別與授權。

結構:

Header.Payload.Signature
  • Header:類型、加密算法
  • Payload:資料(如 userId, email)
  • Signature:加密簽名,防止偽造

JWT 是自包含的(self-contained),可以不用查資料庫就知道用戶資訊。


🪪 五、Token(存取憑證)

Token 是一段字串,用於代表某位使用者的權限與身份。

  • Access Token:讓使用者去存取 API
  • Refresh Token:讓使用者取得新的 Access Token
  • ID Token:用於身份驗證(只有 OIDC 有)

📦 六、Session(伺服器端的登入狀態)

Session 是伺服器上儲存使用者登入狀態的一種方式。

機制:

  1. 使用者登入成功後,伺服器建立一個 Session
  2. 伺服器產生一個 SessionID
  3. 這個 SessionID 會存到使用者的 Cookie 裡

下次請求時會帶上 Cookie,伺服器用這個 ID 去找登入資訊。


🍪 七、Cookie(瀏覽器儲存的小資料)

Cookie 是瀏覽器用來儲存資訊的小檔案,通常用來:

  • 儲存 Session ID
  • 儲存用戶偏好設定
  • 追蹤用戶行為(Analytics)

🛡 八、Cookie 如何防止跨站攻擊(XSS / CSRF)

☠️ XSS(跨站腳本攻擊)

攻擊方式:駭客將惡意 JavaScript 注入頁面,竊取 Cookie 或操作使用者的行為。

✅ 防禦方式:

  • HttpOnly:設定 Cookie 為 HttpOnly,瀏覽器無法透過 JavaScript 存取 Cookie。
  • Content-Security-Policy:限制哪些腳本可以執行,防止注入攻擊。
  • Input Sanitization:所有輸入內容都要嚴格驗證與過濾。

☠️ CSRF(跨站請求偽造)

攻擊方式:使用者登入 A 網站後,駭客在 B 網站中夾帶惡意請求,冒充使用者發送操作。

✅ 防禦方式:

  • SameSite Cookie 屬性:
    • Strict:完全禁止跨站請求帶上 Cookie(最安全)
    • Lax:允許某些安全的 GET 請求
    • None:允許跨站請求,但必須搭配 Secure
  • CSRF Token:每次請求都必須帶上一組難以偽造的隨機字串,用來驗證請求來源。
  • 驗證 Referer / Origin Header:檢查請求來源是否合法。

🔐 九、JWT 與 Cookie 混用的安全策略

在實務上,有些系統會將 JWT 存在 Cookie 中以實現 SSR 的身份驗證與自動帶入。

✅ 建議配置:

  • HttpOnly: 阻止 JavaScript 取得 Token,避免 XSS
  • Secure: 只允許 HTTPS 傳輸,防止中間人攻擊
  • SameSite: 設定為 LaxStrict 以防止 CSRF

❌ 不建議將 Access Token 存在 localStorage:

  • 容易被 JavaScript 存取,暴露在 XSS 風險下

✅ 若使用 Cookie 儲存 JWT:

  • 後端驗證 JWT 的有效性與過期時間
  • 可選擇在 Server 端加強驗證機制,例如 JWT Blacklist 機制

🧠 整體流程總結(用戶登入情境):

  1. 用戶點選「使用 Google 登入」
  2. 被導向到 Google 的 OIDC 認證頁(OAuth 2.0 流程)
  3. 用戶登入後,Google 回傳:
    • Access Token(存取權限)
    • ID Token(身份資訊,JWT)
  4. 應用程式解析 ID Token,確認用戶身份
  5. 前端儲存 Token 或 Server 建立 Session,將 SessionID 寫入 Cookie

🔄 OIDC 是否可以取得 Refresh Token?

答案是:✅ 可以!

但前提是你必須使用正確的授權流程與參數設定。

📌 條件整理

要在 OpenID Connect(OIDC)中取得 Refresh Token,必須滿足以下幾點:

1. 使用授權碼流程(Authorization Code Flow)

  • 最安全、最常見的流程。
  • 支援取得 Access Token、ID Token、Refresh Token。

2. 在 Scope 中加入 offline_access

  • 請求中需包含 scope:
    scope=openid offline_access
    
  • openid 是 OIDC 必要 scope。
  • offline_access 是請求 Refresh Token 的關鍵!

🔄 取得 Refresh Token 的流程(簡化版)

Step 1: 前端導向授權頁

GET https://auth.example.com/authorize?
  response_type=code&
  client_id=abc123&
  redirect_uri=https://your.app/callback&
  scope=openid offline_access profile email

Step 2: 用戶授權後,跳轉回 redirect URI,並附帶 code

Step 3: 後端交換 Token

POST /token
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code&
code=xyz456&
redirect_uri=https://your.app/callback&
client_id=abc123&
client_secret=super-secret

Step 4: Token 回應(包含 Refresh Token)

{
  "access_token": "abc...",
  "id_token": "eyJ...",
  "refresh_token": "xyz...",
  "expires_in": 3600,
  "token_type": "Bearer"
}

⚠️ 注意事項

  • 並不是所有 OIDC 提供者預設會發 refresh_token,需查看服務設定(如 Google、Auth0、Keycloak 等)。
  • 若使用隱式流程(Implicit Flow),不會提供 Refresh Token。
  • 若在前端單頁應用(SPA)中使用,建議搭配 PKCE 流程與安全存儲方式。
  • 某些瀏覽器(例如 Safari)對第三方 Cookie 的限制可能會影響 Token 管理。

🧠 延伸建議

若你正在使用特定 OIDC 提供者(如 Cognito、Auth0、Google OAuth),建議查閱其官方文件,確認:

  • 是否需要額外設定 offline_access
  • 是否預設支援 Refresh Token

若需要範例程式碼(如前端或後端實作),可以再說,我可以補上具體範例 🙌

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment