# OpenID Connect (OIDC) OpenID Connect (OIDC) 是一種在 OAuth 2.0 框架之上運行的開放式身份驗證協議。OIDC 針對消費者,允許個人使用單點登錄 (SSO)訪問使用 OpenID 提供商 (OP)(例如電子郵件提供商或社交網絡)的依賴方站點,以驗證其身份。它為應用程序或服務提供有關用戶的信息、身份驗證的上下文以及對其配置文件信息的訪問權限。 - 角色定義: ![](https://i.imgur.com/Y68ed48.png) - 通常使用流程: ![](https://i.imgur.com/pVZ6h8m.png) ## what is different with OPENID? OpenID是由非營利組織 OpenID Foundation推動的一種開放標準和去中心化的 認證 協議。它允許用戶通過使用第三方身份提供程序 (IDP) 服務的合作站點(稱為依賴方,或 RP)進行身份驗證,從而無需網站管理員提供他們自己的臨時登錄系統,並允許用戶登錄多個不相關的網站,而不必為每個網站設置單獨的身份和密碼。 OpenID Connect 執行許多與 [OpenID 2.0](https://openid.net/specs/openid-authentication-2_0.html) 相同的任務,但以 API 友好的方式執行,並且可供本機和移動應用程序使用。OpenID Connect 定義了用於可靠簽名和加密的可選機制。OAuth 1.0a 和 OpenID 2.0 的集成需要擴展,而在 OpenID Connect 中,OAuth 2.0 功能與協議本身集成在一起。[more info](https://security.stackexchange.com/questions/44797/when-do-you-use-openid-vs-openid-connect) ## Specifications ### Core #### ***ID Token*** ID Token是由JWT所組成透過JWS(簽證)進形實作組要構成有三個部分 part|description ---|--- header|包含簽章使用的演算法,一般常見最簡單的是 HS256,也就是只有一組金鑰做雜湊來產生簽章,要驗證簽章就一定要這組金鑰;另外一種常見的也是今天主題的重點:RS256,RS256 採用非對稱加密的方式,也就是分別會有公私鑰兩組金鑰,通常會在 server 端使用私鑰來簽章,而 client 端則使用公鑰來驗證簽章是否正確。 payload|裡面包含整個 token 的主要資訊。 signature|每個 JWT token 之所以不容易被竄改,都是靠這個簽章運作的,簽章是針對 header 和 payload 所產生的唯一資訊,因此只要有一個地方被竄改,簽章就會不一樣,我們就會視為這是個不合法的 JWT token。 ``` BASE64URL(UTF8(JWS Protected Header)) || '.' || BASE64URL(JWS Payload) || '.' || BASE64URL(JWS Signature) ``` 透過JWT解出來的內容會類似這樣 ![](https://i.imgur.com/5VNon2l.png) [ID token實際上需要透過server提供的公鑰(JWK)進行驗證後,就能知道id token的合法性。](https://fullstackladder.dev/blog/2023/01/28/openid-validate-token-with-rs256-and-jwks/) [這邊提供js sample code](https://viewsonic-ssi.visualstudio.com/myviewboard.com/_git/mvb-auth0?path=/docs/example/jwt/example.js&version=GBdev&anchor=support-flow) ID token的payload必須符合下面定義規範包含所屬參數,各參數的定義如下 parameter|description ---|--- iss|發布者的URL sub|subject identifier。通常用來代表特定End-user的識別碼 aud|token逾傳送的對象。通常會是client ID的形式 exp|id token 到期時間 iat|發布 (issue)的時間 nonce|用來防止replay attack。回傳RP在發出認證請求 (authentication request)時,所攜帶的隨機數 (如果RP有傳送它的話就應該被回傳) c_hash|authorization code的雜湊值。用來驗證其完整性 at_hash|access token的雜湊值。用來驗證其完整性 #### ***Authentication Request*** 使用發現端點查找授權端點的URL。 parameter|description ---|--- response_type |應始終為code。 client_id |註冊在server上的client id redirect_uri |授權完成時響應將發送到的 URI。必須來自此客戶端的預註冊 URI 列表。 scope |客戶端請求授權的範圍的空格分隔列表。所有請求都必須包含openid 。要接收刷新令牌,請包含offline_access。還應包括確定同意類型的特定範圍。 nonce| 用於將客戶端會話與 ID 令牌相關聯並減輕replay attack的字符串值。每個客戶的每個請求必須是唯一的. prompt| 登錄非 offline_access 範圍,同意offline_access 範圍。 state| 用於維護請求和回調之間狀態的不透明值。 ui_locales| BCP47 語言標籤的空格分隔列表。 發起範例 ``` HTTP/1.1 302 Found Location: https://server.example.com/authorize? response_type=code &scope=openid%20profile%20email &client_id=s6BhdRkqt3 &state=af0ifjsldkj &redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb ``` #### ***Token Request*** 使用發現端點查找令牌端點的 URL。 parameter|description ---|--- grant_type |authorization_code或refresh_token,具體取決於代碼的類型。 code |從授權端點返回的授權代碼,或從令牌端點返回的刷新令牌。必須匹配指定的grant_type。 redirect_uri |與請求授權端點相同。 ### Discover 必須在先前指定的路徑上使用 HTTP GET 請求查詢 OpenID 提供者配置文件 ``` GET /.well-known/openid-configuration HTTP/1.1 Host: example.com ``` 欄位| 必要| 說明 ---|---|---| 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 等 - [google discover](https://accounts.google.com/.well-known/openid-configuration) - [azure discover](https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration) ### Authorization Flow - [流程類型](https://viewsonic-ssi.visualstudio.com/myviewboard.com/_git/mvb-auth0?path=/README.md&version=GBdev&_a=preview&anchor=support-flow) ![](https://i.imgur.com/YGVLJe4.png) - 適用情境 ![](https://i.imgur.com/PDR8nJb.png) #### ***CODE + PKCE*** ![](https://i.imgur.com/DP9nMpT.png) 先解釋兩個參數: - Code Verifier: 一個特殊字串,長度限制為 43 ~ 128 之間。 - Code Chanllenge: 透過 SHA 256 將 Code Verifier 轉換過的字串。 接下來要解釋一下,這兩個字串如何能夠讓 OAuth2 的流程中安全性增加。由於 SHA256 是不可逆且較安全的加密模式,並且在資料的傳輸上先提供 Code Chanllenge 再來是 Code Verifier 可以確保著交握的兩端都是同一個人,因為必須要同時都有兩個才能正確地確認。 這樣就算原本的 code 被竊取到了,也會因為無法產生正確的 Code Verifier 讓惡意程式無法竊取到資料。 講簡單就是送出Authentication Request帶入code_chanllenge,當取得code後轉發出Token Request的時候帶入code_verifier,server side透過SHA256比對code_chanllenge是不是由code_verifier產生。如果是就核發access_token。 ### Logout Flow ![](https://i.imgur.com/Yy8I5ez.png) ![](https://i.imgur.com/MnlIQuU.png) ![](https://i.imgur.com/9LGr0lZ.png) ## Development 開發oidc相關驗證功能我認為不要自己開發,除非對文件是非常熟捻,不然正常情況下基本上石做一定會漏東漏西,因為有太多小細節。建議是使用oidc官方認證過的一些opensource進行轉開發,大概80%基本的功能與流程都根據RFC規範已經實作完畢,通常有遺漏實作的都是2019年以後推出新規範,像是open banking所定義的FAPI(Financial-grade API Security Profile)。 ![](https://i.imgur.com/5b60Dll.png) https://openid.net/developers/certified/ https://openid.net/certification/#OPs ## Learning Resource [IT幫幫忙](https://ithelp.ithome.com.tw/users/20102562/ironman/2923?page=3) [Auth0](https://auth0.com/docs/authenticate/login/oidc-conformant-authentication) [azure oidc doc](https://learn.microsoft.com/zh-tw/azure/active-directory/develop/v2-oauth2-auth-code-flow) ###### tags: `oidc` `authentication`