OpenID Connect Core 定義了很完整的身分驗證流程,但一個良好可擴展的協定會是抽象化的,會保留一些細節在未來由其他協定來補充,或是留給實作者定義。
下面簡單列出目前 OpenID Connect 相關的協定文件:
文件 | 簡述 |
---|---|
OpenID Connect Core | 定義 OpenID Connect 的核心功能 |
OpenID Connect Discovery | 定義 Client 取得 OpenID Provider 的 metadata |
OpenID Connect Dynamic Registration | 定義 Client 如何動態跟 OpenID Provider 註冊 |
OAuth 2.0 Multiple Response Types | 為 OAuth2 定義新的多重 response types |
OAuth 2.0 Form Post Response Mode | 定義新的資訊回應的模式,使用 HTTP Post |
OpenID 2.0 to OpenID Connect Migration 1.0 | 如何從 OpenID 2.0 遷移成 OpenID Connect |
下面介紹其中幾個補充協定。
之前有提過 OpenID Connect 或 OAuth2 會提供很多 endpoint 以滿足各種流程運作需要。而做為一個 OpenID Provider,要在教學裡提供這些內容就會顯得有點瑣碎。
OpenID Connect Discovery 正是解決此問題的好方法,它定義 OpenID Provider 需要一個提供 URL 如:
http://example.com/.well-known/openid-configuration
即可回傳 OpenID Provider Metadata:
欄位 | 必要 | 說明 |
---|---|---|
issuer | REQUIRED | 在拿到 ID token 時,iss 會與此欄位的值一樣 |
authorization_endpoint | REQUIRED | OpenID Connect 啟動身分驗證的入口 |
token_endpoint | REQUIRED / OPTIONAL | OpenID Connect 讓 Client 取得 token 的端口。如果只支援 Implicit Flow 則不需要 |
userinfo_endpoint | RECOMMENDED | 透過 token 取得使用者個資的端口 |
jwks_uri | REQUIRED | 這裡會放 JWK Set 的內容,可以使用此內容來作為 JWK 處理,通常這裡放的是公鑰 |
registration_endpoint | RECOMMENDED | 動態註冊的端口 |
scopes_supported | RECOMMENDED | 支援哪些 Scope |
response_types_supported | REQUIRED | 指 response_type 有哪些可以用 |
response_modes_supported | OPTIONAL | 指 response_mode 有哪些可以用 |
grant_types_supported | OPTIONAL | 如 authorization_code 、implicit 等 |
欄位設定有非常多,這裡提幾個來看看。
在註冊完 Client 加上有了這些資訊後,就有辦法跟透過此 OpenID Provider 做身分驗證。包括 Hydra、Google、AppleID、Line 都有辦法串接。
這裡也閒聊一下串接遇到的問題:
jwks_uri
看到的是 ES256,但簽出來的 JWT 是 HS256,後來查文件才知道 secret 是申請 Client 所給的 secret但不管怎麼說,裡面的資訊對於串接服務而言,是足夠使用的。
OpenID Connect Discovery 在定義 OpenID Provider 的 metadata,而 OpenID Connect Dynamic Registration 有部分則是在定義 Client 的 metadata。比方說相關的欄位如下:
欄位 | 必要 | 說明 |
---|---|---|
redirect_uris | REQUIRED | Client 可接受的的轉導向 URI |
response_types | OPTIONAL | 可用的 response type |
grant_types | OPTIONAL | 可用的授權模式 |
application_type | OPTIONAL | 指 web 或 native (App) |
contacts | OPTIONAL | Client 維護者的 email |
client_name | OPTIONAL | Client 名稱 |
logo_uri | OPTIONAL | Client 的 logo |
client_uri | OPTIONAL | Client 的首頁 |
policy_uri | OPTIONAL | Client 要提供給使用者閱讀的隱私權政策 |
欄位設定有非常多,這裡提幾個來看看。
從這裡可以了解,以 OpenID Provider 或 OAuth2 的角度來看,第三方應用程式在註冊的時候,應該要求哪些資訊作記錄。除此之外,像 GitHub Marketplace 也是眾多的 Client metadata 集合起來而成的。
可以回頭去翻閱如 Google 或 Facebook 等授權伺服器的註冊 Client 表單比較看看,大家要求的資訊都相差不多。
註冊完後的回應內容如下:
欄位 | 必要 | 說明 |
---|---|---|
client_id | REQUIRED | Client 的唯一識別碼 |
client_secret | OPTIONAL | Client 驗證用的密碼 |
client_secret_expires_at | OPTIONAL / REQUIRED | 當 client_secret 回傳的話,則必須要提供 secret 什麼時候失效 |
註冊完成即可使用 Client Metadata 配合 OpenID Provider Metadata 來串接身分驗證了。
最後補充一下,OAuth2 也有定義動態註冊可以參考:RFC 7591 - OAuth 2.0 Dynamic Client Registration Protocol,兩個協定都是互相參考,概念上大同小異,就不多討論了。
之前討論 OAuth2 時,有提到授權請求的 response_type
欄位要填 code
,也能填 token
(Implicit Grant)。而這個協定在定義如何摻在一起做 code token
。
首先裡面有提到兩個新的 response type 為 id_token
與 none
。顧名思義,id_token
是回傳帶有 ID Token 參數;none
則是什麼都沒有。
而上述的 type 除了 none
以外,其他三種 type 的組合技如下:
code token
code id_token
id_token token
code id_token token
以最後一個 code id_token token
例子來說,是指回到 redirect uri 時,會把這三個參數一起帶回去。而組合的設計會衍生另一個問題是:順序要怎麼擺才對?類似地,scope
也有這種樣貌,但因為 OAuth2 一開始定義的時候,就是空白隔開的多個授權範圍,所以沒有順序的問題,而 response_type
是定義成字串,才會衍生順序的問題。
筆者建議原則上以協定的順序為主,尤其是要自己實作 OpenID Provider 的時候,更要守規距。除非是實作 Client,且打算完全依賴 Discovery 的資訊(如 Google 的順序就跟協定不同)。
上面都是在討論回傳的內容有什麼,那該如何傳給 Client 呢?因此協定又有另外定義 Response Mode 作為回傳的方法,這裡是將 OAuth2 所定義的方法,再次重新定義成授權請求的新參數 response_mode
:
query
,參數編碼後,作為 redirect_uri
的 query 字串傳遞,通常用在 Authorization Code Grantfragment
,參數編碼後,放在 redirect_uri
的 fragment 傳遞,通常用在 Implicit Grantresponse_mode
可以指定授權伺服器在回應的時候,要用什麼方法傳。(如果授權伺服器有支援的話)
題外話:筆者之前串接過 AppleID,如果沒帶
response_mode
參數,則 AppleID 串接會失敗。
OpenID Connect 除了定義 response_mode
還另外定義了新的方法為 Form POST:
form_post
,參數編碼後,放在 body 裡,然後用自動提交的 Form POST 傳給 Client 的 redirect_uri
。截至目前為止,OpenID Connect 的簡介算告一段落,雖然它還有定義 Implicit Flow 和 Hybrid Flow 沒有講到,但實務上在 Web 上最常使用的是 Authorization Code Flow,相信已能滿足大部分情境需求。