SSO、SAML 與 OIDC
前面幾篇談的是一般第三方登入:
使用 Google 登入
使用 LINE 登入
使用 GitHub 登入但企業登入會再往前一步:
使用公司的身份系統登入例如:
- Okta。
- Microsoft Entra ID。
- Google Workspace。
- OneLogin。
- Auth0 / Azure AD B2C。
- 公司自建 IdP。
這時候問題不只是「使用者是誰」,而是:
這個人屬於哪個公司?
這家公司是否允許他登入?
他在公司裡是什麼角色?
他離職後要不要自動失效?這就是 SSO、SAML、OIDC 進入企業登入設計的地方。
一、 一句話回答
如果面試官問:
SSO、SAML、OIDC 是什麼?差在哪?
可以先回答:
SSO 是單一登入的產品能力,讓使用者登入一次企業身份系統後,可以存取多個服務;SAML 和 OIDC 則是實作 SSO 的常見協議。SAML 2.0 是較早也很常見的企業聯邦身份標準,使用 XML assertion,角色通常叫 IdP 和 SP;OIDC 是建立在 OAuth 2.0 之上的身份層,使用 ID Token、claims、UserInfo,角色通常叫 OP 和 RP。企業登入不只是驗證 token 或 assertion,還要處理 tenant、domain verification、issuer、audience、subject、group/role claims、JIT provisioning、SCIM deprovisioning、IdP initiated / SP initiated flow、session 與權限映射。
短一點可以說:
SSO 是能力;
SAML 和 OIDC 是協議;
企業登入的核心是信任關係、租戶歸屬與帳號生命週期。二、 SSO 是什麼
SSO 是 Single Sign-On,單一登入。
它的目標是:
使用者登入一次身份提供者,
就能使用多個受信任的應用。例如公司員工早上登入 Okta,接著可以進:
- Slack。
- GitHub Enterprise。
- Notion。
- Jira。
- 內部後台。
- HR 系統。
使用者不需要每個系統都各自設定密碼。
SSO 的好處:
- 使用者少記多組密碼。
- 公司可以集中管理登入政策。
- 可統一要求 MFA。
- 員工離職時可集中停用。
- 安全事件可集中稽核。
- 企業採購 SaaS 時更容易治理帳號。
但 SSO 不是魔法。應用系統仍要處理:
- 哪個 tenant 可以用哪個 IdP。
- 使用者第一次登入時要不要建帳號。
- claims 如何映射角色。
- IdP 停用使用者後本地帳號怎麼同步。
- 本地 session 怎麼建立與撤銷。
- 管理員誤設定時如何避免帳號接管。
三、 角色:IdP、SP、OP、RP
在企業登入裡,有幾個名詞一定要分清楚。
| 名稱 | 常見於 | 意義 |
|---|---|---|
| IdP | SAML / 泛稱 | Identity Provider,身份提供者 |
| SP | SAML | Service Provider,服務提供者 |
| OP | OIDC | OpenID Provider,OIDC 身份提供者 |
| RP | OIDC | Relying Party,依賴 OP 身份聲明的應用 |
| Tenant | SaaS 系統 | 公司、組織、工作區或租戶 |
如果用 SAML 說:
Okta 是 IdP。
你的 SaaS 是 SP。如果用 OIDC 說:
Okta / Microsoft Entra ID 是 OP。
你的 SaaS 是 RP。如果用比較通俗的話說:
企業身份系統負責驗證使用者;
你的產品負責信任它的結果,並建立自己的本地登入狀態。四、 SAML 與 OIDC 的差異
| 比較 | SAML 2.0 | OIDC |
|---|---|---|
| 基礎格式 | XML | JSON / JWT |
| 身份聲明 | Assertion | ID Token / claims |
| 常見場景 | 傳統企業 SSO、舊系統、SaaS 採購整合 | 新系統、Web/mobile/API 友善、OAuth 生態 |
| 角色 | IdP / SP | OP / RP |
| metadata | XML metadata | discovery document / JWKS |
| 簽章 | XML Signature | JWT Signature |
| 開發體驗 | 較重,XML 驗證細節多 | 較輕,現代 API 生態友善 |
| 流程 | Browser redirect / POST binding | Authorization Code Flow / PKCE |
面試時不要簡化成:
SAML 舊,OIDC 新,所以 OIDC 一定比較好。比較準確的說法是:
SAML 仍然大量存在於企業 SSO;
OIDC 更適合現代 Web、mobile、API 與 OAuth 生態;
選哪個常取決於客戶 IdP、企業 IT 政策與產品整合成本。很多 B2B SaaS 會兩個都支援。
五、 SP-Initiated 與 IdP-Initiated
SP-Initiated
SP-Initiated 是使用者先從你的產品開始登入:
使用者打開 app.example.com
-> 輸入公司 email 或選 tenant
-> 你的產品導向該公司的 IdP
-> IdP 登入成功後回到你的產品流程比較像:
這是比較容易控制風險的方式,因為你的系統知道:
- 使用者想進哪個 tenant。
- 應該使用哪個 IdP。
- callback 應該對應哪次登入 flow。
- state / relay state 可以綁定流程。
IdP-Initiated
IdP-Initiated 是使用者從 IdP dashboard 點你的應用:
使用者登入 Okta
-> 點你的 SaaS app
-> Okta 直接送 assertion 到你的 ACS endpoint它使用者體驗很好,但風險和複雜度更高:
- 你的產品可能不知道使用者原本想進哪個 tenant。
- request/response 綁定較弱。
- relay state 處理要小心 open redirect。
- 多 tenant 下要能靠 issuer / entity id 判斷來源。
很多企業客戶會要求 IdP-Initiated,但產品要清楚它和 SP-Initiated 的安全差異。
六、 SAML 登入流程
SAML 常見 SP-Initiated 流程:
幾個重要名詞:
| 名稱 | 說明 |
|---|---|
| Entity ID | SP 或 IdP 的唯一識別 |
| SSO URL | IdP 接收登入請求的位置 |
| ACS URL | Assertion Consumer Service,SP 接收 SAMLResponse 的 endpoint |
| SAMLResponse | IdP 回傳的 XML response |
| Assertion | 裡面包含身份聲明、subject、attributes、conditions |
| NameID | SAML 中常見的使用者識別 |
| Metadata | 描述 IdP/SP endpoint、憑證、entity id 等設定 |
驗證 SAML Response 時要注意:
- 簽章是否有效。
- 簽章憑證是否來自該 tenant 設定的 IdP。
- issuer 是否正確。
- audience 是否是你的 SP entity ID。
- recipient / destination 是否是你的 ACS URL。
- assertion 是否過期。
- NotBefore / NotOnOrAfter 是否合理。
- InResponseTo 是否對應本次 AuthnRequest。
- NameID 或 subject 是否穩定。
- attribute mapping 是否符合預期。
不要只解析 XML 拿 email。
SAML 最大的坑之一就是 XML Signature 驗證做錯,或驗了 response 但沒有驗 assertion,或沒有處理 XML wrapping attack。實務上應使用成熟且維護良好的 SAML library,不要自己手寫 XML 簽章驗證。
七、 OIDC 企業登入流程
OIDC 的企業登入本質上和前面講的第三方登入相似,但多了 tenant 與企業政策。
典型流程:
OIDC 驗證重點:
- issuer。
- audience。
- expiration。
- nonce。
- signature / JWKS。
- subject。
- authorized party,若適用。
- email_verified,若使用 email。
- tenant id / organization claim,若 Provider 有提供。
企業 OIDC 的資料模型通常不是:
provider = google而是:
tenant_id = acme
issuer = https://login.microsoftonline.com/{tenant}/v2.0
subject = ...同一個 email 在不同 tenant 下可能代表不同身份,不要只用 email 跨 tenant 合併。
八、 Tenant 與 Domain Verification
B2B SaaS 最重要的問題之一是:
如何知道這個 email 屬於哪個企業 tenant?常見做法:
- 使用者輸入 email。
- 系統取 domain,例如
acme.com。 - 查這個 domain 是否已被某個 tenant 驗證。
- 若該 tenant 啟用 SSO,導向它的 IdP。
但 domain routing 不能只靠字串。
企業要先完成 domain verification,例如:
- DNS TXT record。
- 上傳驗證檔。
- 發送到管理員 email。
- IdP metadata 驗證。
資料模型可以像:
create table tenants (
id uuid primary key,
name text not null,
slug text unique not null
);
create table tenant_domains (
id uuid primary key,
tenant_id uuid not null references tenants(id),
domain text not null,
verified boolean not null default false,
verified_at timestamp,
unique (domain)
);
create table sso_connections (
id uuid primary key,
tenant_id uuid not null references tenants(id),
protocol text not null,
issuer text not null,
entity_id text,
sso_url text,
jwks_uri text,
metadata_url text,
enabled boolean not null default false,
created_at timestamp not null
);重點:
- domain 必須唯一歸屬。
- 未驗證 domain 不能用來自動導向企業 SSO。
- SSO connection 要綁 tenant。
- issuer/entity ID 要綁該 tenant 的設定。
- callback 時要確認回來的 IdP 是該 tenant 預期的 IdP。
九、 JIT Provisioning
JIT 是 Just-In-Time provisioning。
意思是:
使用者第一次透過企業 SSO 登入時,系統自動建立本地帳號。例如 IdP assertion / ID Token 告訴你:
subject = 00u123
email = alice@acme.com
name = Alice
groups = ["engineering"]你的系統可以建立:
tenant = Acme
user = Alice
membership = engineering role
external identity = issuer + subjectJIT 要注意:
- tenant 是否允許 JIT。
- email domain 是否屬於 tenant。
- subject 是否穩定。
- groups 是否可信且已映射。
- 預設角色不能過高。
- 第一次登入是否需要管理員批准。
- 如果同 email 已有本地帳號,是否要合併或要求驗證。
JIT 最常見錯誤是:
只要 SSO 回來就建立 admin。比較安全的做法:
JIT 只建立最低權限 membership,
角色提升由管理員或明確 group mapping 控制。十、 SCIM 與 Deprovisioning
JIT 解決的是「登入時建立帳號」。
但企業更在意的是:
員工離職後,帳號是否會被停用?這就是 SCIM 常出現的地方。
SCIM 是跨系統管理使用者與群組生命週期的協議。企業 IdP 可以透過 SCIM 呼叫你的產品:
- 建立使用者。
- 更新使用者。
- 停用使用者。
- 同步群組。
- 移除 membership。
沒有 SCIM 的系統常遇到:
員工已從公司離職,
但你的 SaaS 裡的 session 還活著。所以企業登入的完整設計通常是:
| 能力 | 解決問題 |
|---|---|
| SSO | 使用企業身份登入 |
| JIT | 第一次登入時建立本地 user |
| SCIM | 從 IdP 同步 user/group 生命週期 |
| Session revocation | 停用後撤銷既有 session |
| Audit log | 追蹤誰登入、誰被停用、誰改權限 |
如果 user 被 SCIM deprovision:
- 停用 membership。
- 撤銷 refresh token。
- 撤銷 active sessions。
- 阻止後續 SSO 登入。
- 保留 audit log。
- 不一定刪除歷史資料,避免資料歸屬消失。
十一、 Groups 與 Role Mapping
企業 IdP 常會傳 group claims:
{
"groups": ["engineering", "admin"]
}但不要無腦把 group 字串當本地權限。
你應該有 mapping:
IdP group "acme-engineering" -> product role "developer"
IdP group "acme-admins" -> product role "admin"原因:
- 不同企業 group 命名不同。
- group 名稱可能被改。
- 有些 Provider 傳 group id,有些傳 group name。
- group claim 可能太大而需要另外查 API。
- admin 權限應該可被產品管理員確認。
比較好的模型:
create table sso_group_mappings (
id uuid primary key,
tenant_id uuid not null references tenants(id),
sso_connection_id uuid not null references sso_connections(id),
external_group text not null,
product_role text not null,
unique (tenant_id, sso_connection_id, external_group)
);登入時:
驗證 assertion/token -> 取得 groups -> 套用 mapping -> 更新 membership roles高權限 role 建議:
- 要有明確 mapping。
- 預設不自動給 admin。
- 變更 mapping 要記 audit log。
- 對 admin role 可要求額外確認。
十二、 SSO 與本地 Session
SSO 成功後,你的產品仍然要建立自己的 session。
不要每次 API request 都去問 IdP:
這個使用者現在還登入嗎?常見做法:
SSO 驗證成功 -> 建立本地 session -> 後續 API 使用本地 session但要注意企業停用同步:
- 若 SCIM 停用 user,要撤銷 session。
- 若 tenant 關閉 SSO,要重新評估登入方式。
- 若 user role 改變,session 中的權限要能更新。
- 若 IdP 發出 logout 事件,視協議支援處理 SLO。
SAML 有 Single Logout 機制,但實務整合常比想像複雜,不一定每個 IdP / SP 都可靠支援。很多產品會以本地 session 管理、SCIM deprovision、短效 session 和風險控制為主。
十三、 Multi-tenant 風險
企業登入最危險的錯誤之一是 tenant mix-up。
例如:
使用者從 tenant A 的 IdP 登入,
結果被放進 tenant B。防線:
- SSO connection 必須綁 tenant。
- issuer/entity ID 必須符合 tenant 設定。
- domain routing 只使用 verified domain。
- callback state 綁定 tenant id。
- subject 只在 issuer 下有效。
- email 不可跨 tenant 自動合併。
- group mapping 必須 tenant-scoped。
資料庫唯一鍵也要考慮 tenant:
unique (tenant_id, issuer, subject)或:
unique (sso_connection_id, subject)避免不同企業 IdP 的 subject 撞在一起。
十四、 常見錯誤
1. 只用 email 決定 tenant
錯誤:
看到 alice@acme.com,就放進 Acme tenant。正確:
domain 必須被 tenant 驗證,SSO callback 也要驗 issuer/entity ID。2. SAML 只 parse 不驗簽
錯誤:
解析 SAMLResponse XML,拿 NameID 和 email 建 session。正確:
驗簽章、issuer、audience、recipient、destination、conditions、InResponseTo。3. OIDC 只 decode ID Token
錯誤:
jwtDecode(id_token)正確:
驗 JWKS 簽章、issuer、audience、exp、nonce、subject。4. JIT 預設給高權限
錯誤:
第一次 SSO 登入就給 admin。正確:
預設最低權限,高權限由 group mapping 或管理員確認。5. 沒有 deprovision
錯誤:
SSO 能登入就好,離職不管。正確:
支援 SCIM 或停用同步,並撤銷本地 session。6. 忽略 IdP-Initiated 風險
錯誤:
任何 SAMLResponse POST 到 ACS 都接受。正確:
根據 issuer/entity ID 找 tenant,驗簽與 audience,限制 relay state,並防 tenant mix-up。十五、 面試追問題庫
Q1:SSO、SAML、OIDC 的關係是什麼?
SSO 是單一登入能力,SAML 和 OIDC 是常見實作協議。SAML 使用 XML assertion,常見角色是 IdP / SP;OIDC 建立在 OAuth 2.0 上,使用 ID Token 和 claims,常見角色是 OP / RP。
Q2:SAML 和 OIDC 怎麼選?
如果客戶是傳統企業、既有 IdP 或舊 SaaS 生態,SAML 仍很常見。如果是新系統、mobile、API 或 OAuth 生態,OIDC 通常更友善。B2B SaaS 常會兩者都支援,因為真正決定的是客戶 IdP 能力與企業 IT 政策。
Q3:企業 SSO 為什麼不能只看 email?
因為 email 是屬性,不是聯邦身份主鍵。同一 email 可能出現在不同 tenant,email 也可能變更。企業 SSO 應使用 tenant + issuer/entity ID + subject/NameID 建立身份映射。
Q4:什麼是 JIT provisioning?
JIT 是使用者第一次透過 SSO 登入時,系統根據 IdP assertion/token 自動建立本地 user 或 tenant membership。它要搭配最低權限、domain/tenant 驗證與 group mapping,避免第一次登入就取得過高權限。
Q5:SCIM 解決什麼問題?
SCIM 解決使用者與群組的生命週期同步,例如建立、更新、停用、群組同步。它特別重要的是 deprovisioning:員工離職或被移出群組後,你的產品要停用帳號、撤銷 session 或更新權限。
Q6:IdP-Initiated SSO 有什麼風險?
IdP-Initiated 是使用者從 IdP dashboard 點 app,IdP 直接送 assertion 給 SP。它體驗好,但 request/response 綁定較弱,多 tenant 下要更小心 issuer/entity ID、relay state、audience、tenant routing 與 open redirect。
Q7:SSO 成功後,還需要本地 session 嗎?
需要。SSO 只證明外部身份驗證成功;你的產品仍要建立自己的 session,並負責權限、撤銷、session 有效期、裝置管理、audit log 與本地安全策略。
十六、 實作題
題目一:設計企業 SSO connection 資料表
請支援:
- 一個 tenant 多個 SSO connection。
- 支援 SAML 與 OIDC。
- domain verification。
- issuer/entity ID 驗證。
- 啟用 / 停用。
可以從這些表開始:
tenants
tenant_domains
sso_connections
sso_group_mappings
tenant_memberships題目二:設計 SP-Initiated SAML 登入
請描述:
- 使用者輸入 email 或 tenant slug。
- 找到 verified domain / tenant。
- 找到 tenant 的 SAML connection。
- 產生 AuthnRequest 與 RelayState。
- Redirect 到 IdP。
- ACS 收到 SAMLResponse。
- 驗簽章、issuer、audience、destination、conditions、InResponseTo。
- 使用 issuer + NameID/subject 找 external identity。
- JIT 建立 user/membership。
- 建立本地 session。
題目三:設計 deprovision 流程
情境:
企業 IdP 通知使用者 alice@acme.com 已停用。請設計你的產品要做什麼。
好的答案應包含:
- 停用 tenant membership。
- 撤銷 refresh token。
- 撤銷 active sessions。
- 保留 audit log。
- 不刪歷史資料。
- 阻止後續 SSO 登入。
- 必要時通知 tenant admin。
十七、 資深視角
1. SSO 是信任關係,不只是登入按鈕
企業 SSO 的本質是:
你的產品信任某個企業 IdP 對某個 tenant 的身份聲明。所以你要驗的是:
- 是不是這個 IdP。
- 是不是這個 tenant。
- assertion/token 是不是給你的產品。
- 使用者 subject 是否穩定。
- claims 是否符合政策。
2. 租戶邊界比登入成功更重要
登入成功只代表使用者通過 IdP。
但 B2B SaaS 還要問:
他能不能進這個 workspace?
他是不是這個 tenant 的成員?
他是不是 admin?
他是否已被停用?tenant boundary 錯,比登入失敗更嚴重。
3. 身份、成員資格、權限要分開
好的模型通常會拆成:
User:全域使用者
ExternalIdentity:外部身份
TenantMembership:使用者在某 tenant 的成員資格
Role/Permission:在 tenant 內能做什麼
Session:這次登入狀態不要把 SSO subject 直接等同於全域 user,也不要把 email 直接等同於 tenant membership。
4. 企業登入的完整性在生命週期
能登入只是開始。
真正成熟的企業身份整合要處理:
- onboarding。
- JIT。
- group mapping。
- role sync。
- deprovisioning。
- session revocation。
- audit log。
- admin recovery。
- IdP metadata rotation。
- certificate rotation。
這些才是資深工程師在系統設計題裡應該補上的部分。
總結
| 問題 | 回答重點 |
|---|---|
| SSO | 單一登入能力 |
| SAML | XML assertion,企業 SSO 常見 |
| OIDC | OAuth 2.0 上的身份層,ID Token / claims |
| IdP / SP | SAML 的身份提供者與服務提供者 |
| OP / RP | OIDC 的身份提供者與依賴方 |
| Tenant | 企業、組織、工作區邊界 |
| JIT | 第一次 SSO 登入時建立 user/membership |
| SCIM | 同步 user/group 生命週期與停用 |
| 最大風險 | tenant mix-up、只信 email、不驗簽、不處理 deprovision |
一句完整的面試回答可以是:
SSO 是單一登入能力,SAML 和 OIDC 是常見的企業 SSO 協議。SAML 2.0 使用 XML assertion,角色是 IdP 和 SP;OIDC 建立在 OAuth 2.0 上,使用 ID Token、claims、UserInfo,角色是 OP 和 RP。企業登入不只是驗證使用者身份,還要確認 tenant 邊界與信任關係,例如 issuer/entity ID、audience、subject/NameID、domain verification、group mapping 與本地 membership。實作時應使用成熟 library 驗證 SAML 簽章或 OIDC ID Token,不能只 parse email;SSO 成功後仍要建立本地 session,並處理 JIT provisioning、SCIM deprovisioning、session 撤銷、audit log 與角色映射。資深設計會把 User、ExternalIdentity、TenantMembership、Role、Session 分開,避免 tenant mix-up 和 account takeover。