每當點選社群帳號登入,背後發生了什麼事?
Hihi~ 上次介紹完線上認證授權技術兩本柱中的 OAuth 2.0,這次要跟大家介紹的是 OpenID Connect (OIDC) 。相較於 OAuth 2.0 提供的授權機制,OIDC 提供的認證功能,在大家日常生活中可能會更常用到喔!上圖是大家出國玩常用到的 Booking.com ,你可以看到她的註冊畫面可以選擇用 Facebook 或 Google 登入,是不是很熟悉呢?
這種可以用妳原有的帳號,登入其他網站或應用的功能,就稱為社群帳號登入(Social Login)。
OpenID Connect,就是實現 Social Login 的核心技術。
本文將對 ODIC 概念及機制做介紹,最後同樣以 LINE 提供的 OpenID Connect 服務:LINE Login 為例,demo 認證機制運作的實際流程。
邀您一起探索,每當點選社群帳號登入,發生在背後的奧秘!
The OpenID Connect Standard
OpenID Connect (OIDC) 規範了一個認證的標準機制,這個認證機制主要適用於線上服務情境。在這個機制中,服務提供者及認證提供者可以來自不同的廠商,因此能作到像是 Social Login這樣的功能。
對 end user 來說,OIDC 最大的好處就是讓我們想要嘗試新的線上應用或 App 的時候,可以使用其他網站既有的帳號登入,不用每次重複填寫個人資料。此外,個資也更有保障,因為可以選擇讓帳號密碼只註冊在有信譽的馳名服務提供者,不會散落於不知名的線上應用業者手中。
那對開發者有什麼好處呢?顯而易見的就是讓用戶更容易從 Landing Page 轉換去使用您的服務。技術方面,藉由這個廣泛被採用支持的標準,開發者可以相同的 code base 來實做相關功能。
DevOps 正夯,也來說一說關於營維運的部份。OIDC 讓認證機制可以委外由可信賴的業者提供,這其實大幅降低維運的風險及成本。怎麼說呢?過去習於要求使用者自負使用服務的資安風險,所以會有很多亂七八糟的密碼規則限制用戶。而今資安的責任逐漸轉移至服務提供者,一個代表性的指標就是 NIST 新版的 800–63 號 《電子驗證指導原則》。在這份文件中,要求服務提供者不應對用戶施加密碼規則,而是要求服務端以各種方式抵擋密碼外洩及設計抵抗暴力破解的機制。說起來容易,要抵禦變化多端的攻擊手法對營運商是一大考驗。所以藉由 OIDC 委外認證,對用戶及服務提供者都更有保障,講白點至少出包的時候可以說密碼不是從我們這邊外洩的 lol。
Q&A 時間
1. OpenID Connect 和 OAuth 2.0 有什麼不一樣?
OIDC 和 OAuth 2.0 兩者在目的上有很大的區別。OIDC 目的是認證(Authentication),OAuth 2.0 目的則是授權(Authorization)。然而兩者在機制上卻大致雷同,後面會講到,OIDC 正是建構在 OAuth 2.0 framework 的基礎上面。
另一個不太重要的不同點是,OAuth 2.0 是提交到 IETF 發布的 RFC,OIDC 則是由 OpenID Foundation 維護。
2. OpenID Connect 和 OpenID 1.0/1.1/2.0 有什麼關聯?
OpenID 家族的協定都是由 OpenID Foundation 發布維護。這些名字很像的標準目的也都相同:規範線上服務的認證機制。
雖然目的相同,但機制上 ODIC 卻和它的前輩們有很大的不一樣。主要的差異就是前面有提到 ODIC 是架構在 OAuth 2.0 之上,OpenID 1.0/1.1/2.0 則是獨立的協定。
必須提一下,OpenID 最早是由目前活躍於 Golang 社群的大神:Brad Fitzpatrick 所開創。這位大大還建立很多知名的開源專案,例如 Memcached 和我之前介紹過得 MogileFS。偉哉!
OIDC Mechanisms
前面講到 OIDC 只是 OAuth 2.0 的擴充,因此要瞭解 OIDC 機制,首先要知道她比 OAuth 2.0 新增哪些元素。
ODIC 擴充元素
ODIC 彌補了 OAuth 2.0 在實務上許多不足的地方,其中最重要的是擴充以下幾個元素:
- ID Token:認證所需的用戶資訊,這是 OIDC 最重要的擴充。不要和 OAuth 2.0 的 Access Token 攪混了,Access Token 是用於授權,不帶有用戶資訊來做認證。
- UserInfo Endpoint:除了上面 ID Token 提供基本用戶資訊,OIDC 還規定認證提供者應提供一個 API 界面,讓 Client 能取的更完整的用戶資訊。
- Standard Set of Scopes:OAuth 2.0 沒有定義 scope(忘記這是什麼了嗎?先回去看一下前一篇文章吧!),造成 Facebook 可能有 Facebook 的 scope,Google 有 Google 的 scope,實做的時候必須參閱各家的手冊客製化。OIDC 規範了共通的 scope 讓大家有規可循。詳細規範可以參考文件。
OIDC Flow
這邊會將上述新增的項目,代入到流程之中。建議先閱讀上一篇文章,會比較容易理解這裡的流程。
流程圖將 OIDC 變動的部份醒目標示。第一個變化是第 2 步在要求 Authorization Code 的時候,scope
新增了 openid
值。
第二個不一樣的地方,是第 8 步在換 Access Token 的時候,除了取得 Access Token,還取得了 ID Token。這是因為前面的scope
有指定 openid
,讓 Client 有取得 ID Token 的權限。
最後的差異是第 10 步。先前 OAuth 2.0 的流程在取得授權後是去存取用戶持有的資源(用戶的照片、文件等等),但 OIDC 的目的是認證。這邊是從 OIDC UserInfo Endpoint 取得認證所需的用戶資訊,來完成註冊的流程。
更多 ODIC 冷知識
- ODIC 其實有把流程中的角色和物件重新定義專有名詞,但這邊還是沿用 OAuth 2.0 的term。這邊不多介紹,有興趣可以參考這裡。
- 上面介紹的 ID Token,是以 JSON Web Token (JTW)格式編碼,實做需要對其編碼格式稍加瞭解或是直接配合使用 JTW library 才能拿到用戶資訊喔!
DEMO:LINE Login
光說不練是不行的,現在讓我們實際操作 OIDC 的機制看看吧!前面的介紹知道 OIDC 是架構在 OAuth 2.0 之上,因此整個流程和 OAuth 2.0 有 87 分像。流程同樣先取得 Authorization Code ,但下一步除了取得 Access Token ,還必須取得 OIDC 新增的 ID Token。
這邊同樣提醒,LINE Login 官方手冊 已經人很好的提供了詳盡的步驟,如果只是要導入 LINE Login 可以直接看官方手冊。這邊 DEMO 主要的目的是用 OpenID Connect debugger 這個工具,以無關程式語言,公平公正公開的方式示範 OIDC 流程。最後補上測試過程中發現的一些 LINE Login 實作細節分析,供有經驗的讀者參考。
一、LINE Login 應用設定
這邊沿用上一篇文章示範的 LINE Login 應用 play-line-login。唯一要修改的地方在 App Setting 分頁,將 Callback URL 改為 https://oidcdebugger.com/debug
二、取得 Authorization code
這個步驟與之前相同,OpenID Connect debugger 扮演 Client ,LINE Login 則作為 Authorization Server 。
首先我們開啟 OpenID Connect debugger,並填入相關資訊。其中 Authorize URL 要填入 LINE Login endpoint 位置: https://access.line.me/oauth2/v2.1/authorize,Client ID 填入 LINE Login Channel ID。
這邊要注意 scope 的欄位是 openid ,這樣才可以跑 OIDC 的流程。
填寫完成按送出就會開始流程。首先會被導到 LINE 登入畫面。登入讓 LINE 知道你是誰以後,接下來會發現,這邊要求的權限變成了「用戶識別資訊」,這應變了當初填入的 scope 而有所變化。請選【是】繼續流程。
接下來畫面跳轉回 Debugger。顯示已經成功取得 Authorization Code 了 🎉 🎉 🎉,就是畫面中綠標的位置。
三、使用 Authorization Code 換得 Access Token 和 ID Token
接下來我們要去取得 Access Token 和 OIDC 新增的 ID Token。這步驟需要的參數 debugger 已經幫我們準備好了,只需自行代入 client_secret
。
這邊以 curl 發送後,可以看到成功取得 Access Token 和 ID Token。
ID Token 是以 JWT 編碼,解碼後如下:
其中 iss
說明這是由 LINE 發出的使用者識別資訊,sub
是這個用戶在 LINE 的唯一識別 ID,兩者連接起來就是用戶在網路上唯一的識別 ID。
利用上述流程及這個識別 ID ,就可以做出像這樣的 LINE 登入功能拉:
另外也可以打開 LINE App,觀察用來測試的帳號資訊,應該可以看到前面步驟確實使 play-line-login 與這個帳號連動了。
LINE Login 實作細節分析及注意事項
最後整理一些測試過程中發現的LINE Login實作細節,包含和 OAuth 2.0 / OIDC spec. 差異,以及官方文件沒有明顯提示的部份。前面都是一些比較科普的,這邊的資訊大概是這篇文章對有經驗的讀者比較有價值的部分吧。
首先是取 authorization code 的部分:
- response_type 只接受 “code”。:在 OAuth 2.0 四種流程中,LINE 只支援只支援 Authorization code flow,其他三種不支援。當然流程不是支援越多越好,對 LINE Login 來說,或許只需要支援一種流程,即可滿足其業務需求。此外,Authorization code flow 也是相對來說安全性最高的一個流程。
- state 必填:否則會報錯。在 OAuth 2.0 spec. 中這個欄位是選用的,但在實務上為了確保資安,這個欄位必須仔細填寫,這點是 LINE 幫開發者設想周到的部分。欲知詳情,可以參考這邊的討論。
- Response_mode:Only ‘query’ or ‘form_post’ or absent value is supported for ‘response_mode.’ 這個欄位不在原始的 OAuth 2.0 規範,查了一下是由 OAuth 2.0 Multiple Response Type Encoding Practices 這份 Spec. 定義。
- Email scope:LINE Login scope 支援 profile、openid、email 三種值。最後一個 email scope 使用上有些秘訣:1.必須先在 LINE Developer Console 開通 2. email scope 必須連同 openid 一起使用,否則會報錯。
- 提供和自家服務整合的特異功能:在取 authrization code 的 API 中有一些 LINE Login 自訂的欄位,像是
bot_prompt
,功能是讓第三方應用可以在取得授權時順便加用戶好友!這應該也算是便利開發者的小捷徑吧!
取 Access Token 和 ID Token 部份:
- Authorization Code 只能換一次:第二次會回傳 invalid_grant,這應該很多人講過了。
- Email會包含在 ID Token:若前面取 Authorization Token 的時候有要求存取 email scope,這邊取得的 ID Token 就會包含用戶 email 的資訊。
TL; DR
OpenID Connect 補足 OAuth 2.0 沒有規範的 Authentication Mechanism 部份,使得 Social Login 更容易實現。開發者導入像是 LINE Login 這種 OIDC+OAuth 2.0 雙劍合璧的解決方案,可以更容易實做強健易用的認證授權功能。