Day05 與本文使用的都是 SAML Assertion(SAML 驗證聲明,也就是由 IdP 簽發的身份證明),但用途並不相同。
在 SSO 流程中,SAML Assertion 是使用者完成登入後的身份驗證結果(Authentication Result)。IdP 透過瀏覽器將它傳給 SP,SP 驗證後便建立使用者的登入狀態。
在本文介紹的 SAML 2.0 Bearer 流程中,Client 則將已取得的 SAML Assertion 送到 OAuth 2.0 的 Token 端點,用來交換 Access Token。這通常是後端系統之間的處理流程,不需要使用者再次登入,也不依賴瀏覽器重新導向。
簡單來說,同樣是 SAML Assertion,SSO 把它當登入結果;SAML 2.0 Bearer 則把它當換取 Access Token 的輸入憑證。
今天內容涵蓋:
Day05 講過,很多企業內部系統早就用 SAML 做 SSO:員工開瀏覽器,被導到 SAML IdP 登入,IdP 簽發一份 SAML Assertion 送回應用程式,使用者就進去了。但這一切都建立在「有瀏覽器、有使用者在場」的前提上。
現實中還有另一種情境:某個系統(可能是 API Gateway、後端服務、中介層)手上已經有一張代表某個使用者身份的 SAML Assertion,但接下來要呼叫的 API 只接受 OAuth 2.0 的 Access Token,不認得 SAML Assertion。此時使用者身份已完成驗證,整體流程通常也不涉及瀏覽器,因此無須再次登入或重新導向。
SAML 2.0 Bearer 擴展機制(RFC 7522) 要解決的就是這個問題:讓 Client 拿著一張已簽署、來自受信任 IdP 的 SAML Assertion,直接向 OAuth 2.0 的 Token 端點換一個 Access Token。它和 Day14 的 JWT Bearer 解決的是同一類問題,差別只在 Assertion 的格式是 XML 的 SAML 還是 JSON 的 JWT。
OAuth 2.0 先制定了一套共通的 Assertion Framework(身份聲明框架),說明 Client 如何使用既有的身份聲明交換 Access Token,或證明 Client 自身的身份。這套框架只定義共同的使用方式,並不限制身份聲明必須採用哪一種格式。
SAML 2.0 Bearer 與 Day14 介紹的 JWT Bearer 都依循這套框架。兩者的核心用途相近,主要差別在於資料格式與常見使用情境:
| 比較項目 | SAML 2.0 Bearer | JWT Bearer |
|---|---|---|
| 身份聲明格式 | SAML Assertion(XML) | JWT(JSON) |
| Token 交換類型 | saml2-bearer |
jwt-bearer |
| 常見來源 | 企業 SAML IdP、既有企業系統 | OAuth/OIDC 系統、Service Account |
| 常見情境 | 既有企業系統銜接 OAuth | 後端服務與自動化程式存取 API |
兩者都可以用來交換 Access Token,或作為 Client 身份驗證的依據,也都必須檢查簽發者、受眾、有效期限與簽章。兩者核心概念大致相同,主要差在憑證格式。
Day14 已介紹過 JWT Bearer 可以作為授權依據,也可以用來驗證 Client 身份。SAML 2.0 Bearer 沿用相同設計,因此這裡不再重複說明兩種用途,而是聚焦於改用 SAML Assertion 後的差異。
| 用途 | Token Request 參數 | Day14 的 JWT 表示方式 | 本文的 SAML 表示方式 |
|---|---|---|---|
| 作為授權依據 | assertion |
透過 sub 表示使用者或服務身份 |
透過 Subject/NameID 表示使用者或資源擁有者 |
| 驗證 Client 身份 | client_assertion |
sub 對應 Client 的 client_id |
Subject/NameID 對應 Client 的 client_id |
可以看出,兩種機制使用的參數與用途並沒有改變,真正不同的是憑證格式與欄位名稱:
iss、sub、aud、exp 等 Claims 表達身份與使用限制。Issuer、Subject、AudienceRestriction、NotOnOrAfter 等元素表達相同概念,並另外檢查 Recipient 是否指向正確的 Token 端點。SAML 2.0 Bearer 的交換流程與 Day14 的 JWT Bearer 幾乎相同;兩者真正的差異不在流程,而在於送入 Token 端點的憑證格式與驗證方式。

因此,這裡不再重複拆解與 Day14 相同的流程,只整理改用 SAML Assertion 後需要注意的部分:
assertion 參數,但 grant_type 分別是 jwt-bearer 與 saml2-bearer。iss、sub、aud、exp;SAML 則使用 Issuer、Subject、AudienceRestriction 與 NotOnOrAfter。Recipient 是否指向正確的 Token 端點,以及 Assertion 是否已被重複使用。Token Request 的核心參數如下:
grant_type=urn:ietf:params:oauth:grant-type:saml2-bearer
&assertion={base64url-encoded-saml-assertion}
其中 assertion 就是那份已簽署並經過 Base64url 編碼的 SAML Assertion,是交換 Access Token 的輸入憑證,不會直接用來呼叫 API。SAML Assertion 內最重要的資訊包括:
| 元素/屬性 | 必要性 | 用途 |
|---|---|---|
Issuer |
必填 | 誰簽發這份 SAML Assertion |
Subject/NameID |
必填 | Assertion 代表哪個使用者或 Client |
AudienceRestriction/Audience |
必填 | 這份 Assertion 要交給哪個 Authorization Server |
SubjectConfirmation |
必填 | 確認這是一份 Bearer Assertion |
NotOnOrAfter |
必填 | Assertion 何時失效 |
Recipient |
條件式 | 指定接收 Assertion 的 Token 端點 |
Signature |
必填 | 證明來源可信,且內容未遭竄改 |
只要簽章無效、Assertion 已過期或使用對象不符,請求就會被拒絕;驗證成功後,則會收到一般的 Access Token 回應:
{
"access_token": "eyJh...R76eO",
"token_type": "Bearer",
"expires_in": 3600
}
💡安全提醒: Authorization Server 必須確認 Assertion 由受信任的 IdP 簽發,並驗證 XML 簽章、
Audience、Recipient與有效期限;同時記錄已使用的 Assertion ID,避免重放攻擊。
兩者使用相同的 SAML Assertion 格式,但目的與傳輸方式不同:
| 比較項目 | Day05 SSO(Web Browser SSO Profile) | Day15 SAML 2.0 Bearer(RFC 7522) |
|---|---|---|
| 使用場景 | 使用者用瀏覽器登入 Web 應用程式 | 系統/服務拿已有的 SAML Assertion 去換 OAuth Access Token |
| Assertion 的角色 | 直接就是「登入結果」,SP 收到後直接信任、建立登入狀態 | 只是換票的輸入憑證,最後真正拿去呼叫 API 的是換回來的 Access Token |
| 傳輸方式 | HTTP Redirect(送 AuthnRequest)/HTTP POST(送 Assertion),都經過瀏覽器 |
直接 POST 到 OAuth Token 端點(application/x-www-form-urlencoded),走後端對後端 |
| 是否需要瀏覽器 | 需要,Redirect/POST binding 都依賴瀏覽器重新導向 | 通常不需要,使用者不會感覺到這個過程在發生 |
| 換回來的東西 | SAML Assertion 本身 | OAuth 2.0 Access Token |
| 目的 | 讓使用者「登入一次、多處通行」 | 讓已經存在的身份驗證結果,延伸到 OAuth 保護的 API/資源 |
SAML 2.0 Bearer 是拿已簽署的 SAML Assertion,向 OAuth 2.0 的 Token 端點交換 Access Token,讓既有身份驗證結果延伸到 OAuth 保護的 API。
本文的重點可歸納為以下三項:
下一篇要看的是 Token Exchange(RFC 8693),把「拿既有憑證換 Access Token」這個概念做得更通用,不限定輸入輸出格式,還會明確定義「模擬」跟「委派」兩種語意,特別適合微服務之間互相呼叫的場景。