連結帳戶登入

Google 帳戶連結功能可讓 Google 帳戶持有人快速輕鬆地連結您的服務,並與 Google 共用資料。

透過「連結帳戶登入」功能,如果您已將 Google 帳戶連結到您的服務,使用者就能啟用 One Tap 登入功能。如此一來,使用者只要按一下就能登入,不必重新輸入使用者名稱和密碼,也能享有更優質的體驗。同時降低使用者在您的服務上建立重複帳戶的機率。

需求條件

如要導入已連結帳戶的登入功能,您必須滿足下列條件:

  • 您有支援 OAuth 2.0 授權碼流程的 Google 帳戶 OAuth 連結實作。您的 OAuth 實作項目必須包含下列端點:
    • 授權端點,處理授權要求。
    • 權杖端點來處理存取權和更新權杖的要求。
    • userinfo 端點:擷取已連結使用者的基本帳戶資訊,這些資訊會在已連結帳戶的登入過程中向使用者顯示。
  • 您有 Android 應用程式。

運作方式

事前準備 :使用者先前已將 Google 帳戶與您服務中的帳戶建立連結。

  1. 您在 One Tap 登入流程中,選擇顯示已連結帳戶。
  2. 系統會向使用者顯示 One Tap 登入提示,並提供可透過已連結帳戶登入服務的選項。
  3. 如果使用者選擇繼續使用已連結帳戶,Google 會傳送要求至您的權杖端點,以便儲存授權碼。該要求包含您服務核發的使用者存取權杖和 Google 授權碼。
  4. 你將 Google 授權碼換成 Google ID 權杖,其中含有使用者 Google 帳戶的相關資訊。
  5. 流程完成後,應用程式也會收到 ID 符記,並將此 ID 與伺服器收到的 ID 權杖中的使用者 ID 進行比對,以便使用者登入應用程式。
已連結帳戶登入。
圖 1.已連結帳戶的登入流程。如果使用者在裝置上有多個已登入的帳戶,使用者可能會看到帳戶選擇工具,只有在選取已連結帳戶時,才會導向「已連結帳戶的登入畫面」。

在 Android 應用程式中實作已連結帳戶登入

如要在 Android 應用程式中支援已連結帳戶登入功能,請按照 Android 導入指南中的指示操作。

處理 Google 提出的授權碼要求

Google 向權杖端點傳送 POST 要求來儲存授權碼,以交換使用者 ID 權杖。這項要求內含使用者的存取權杖和 Google 核發的 OAuth2 授權碼。

儲存授權碼之前,您必須驗證您是否將存取權杖授予 Google (由 client_id 識別)。

HTTP 要求

要求範例

POST /token HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded

code=GOOGLE_AUTHORIZATION_CODE
&grant_type=urn:ietf:params:oauth:grant-type:reciprocal
&client_id=CLIENT_ID
&client_secret=CLIENT_SECRET
&access_token=ACCESS_TOKEN

您的權杖交換端點必須能夠處理下列要求參數:

權杖端點參數
code 必要的 Google OAuth2 授權碼
client_id 必填:核發給 Google 的用戶端 ID
client_secret 必填:您核發給 Google 的用戶端密鑰
access_token 必填。您將使用這些資料取得使用者的情境
grant_type 必填:值必須設為 urn:ietf:params:oauth:grant-type:reciprocal

您的權杖交換端點應按照下列步驟回應 POST 要求:

  • 請確認「client_id」已將 access_token 授予 Google。
  • 如果請求有效,並已成功交換 Google ID 權杖以兌換驗證碼,請回應 HTTP 200 (OK) 回應;若要求無效,則會傳回 HTTP 錯誤代碼。

HTTP 回應

成功

傳回 HTTP 狀態碼 200 OK

成功回應範例
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache
{}

錯誤

如果 HTTP 要求無效,請回應下列其中一個 HTTP 錯誤代碼:

HTTP 狀態碼 內文 說明
400 {"error": "invalid_request"} 要求缺少一個參數,因此伺服器無法繼續執行要求。如果要求包含不支援的參數或重複參數,也可能會傳回這個錯誤
401 {"error": "invalid_request"} 用戶端驗證失敗,例如要求包含無效的用戶端 ID 或密鑰
401 {"error": "invalid_token"}

在回應標頭中加入「WWW-Authentication: Bearer」驗證驗證問題

合作夥伴存取權杖無效。
403 {"error": "insufficient_permission"}

在回應標頭中加入「WWW-Authentication: Bearer」驗證驗證問題

合作夥伴存取權杖未包含執行反向 OAuth 所需的範圍
500 {"error": "internal_error"} 伺服器錯誤

錯誤回應應包含下列欄位:

錯誤回應欄位
error 必填錯誤字串
error_description 使用者容易理解的錯誤說明
error_uri 提供錯誤詳情的 URI
錯誤 400 回應範例
HTTP/1.1 400 Bad Request
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache

{
  "error": "invalid_request",
  "error_description": "Request was missing the 'access_token' parameter."
}

交換 ID 權杖的授權碼

您必須用收到的授權碼交換 Google ID 權杖,其中含有使用者的 Google 帳戶相關資訊。

如要交換 Google ID 權杖的授權碼,請呼叫 https://oauth2.googleapis.com/token 端點,並設定下列參數:

要求欄位
client_id 必填:從 API 控制台的「憑證」頁面取得的用戶端 ID。這通常會是名為「New Actions on Google App」的憑證
client_secret 必填 從 API 控制台的「憑證」頁面取得的用戶端密鑰
code 必填。初始要求中傳送的授權碼
grant_type 必要 根據 OAuth 2.0 規格的定義,這個欄位的值必須設為 authorization_code
要求範例
POST /oauth2/v4/token HTTP/1.1
Host: www.googleapis.com
Content-Type: application/x-www-form-urlencoded

code=GOOGLE_AUTHORIZATION_CODE
&grant_type=authorization_code
&client_id=GOOGLE_CLIENT_ID
&client_secret=GOOGLE_CLIENT_SECRET

針對這項要求,Google 會傳回包含短期存取權杖和更新權杖的 JSON 物件。

回應會包含以下欄位:

回應欄位
access_token 您的應用程式傳送 Google 核發的存取權杖,用於授權 Google API 要求
id_token ID 權杖包含使用者的 Google 帳戶資訊。「驗證回應」部分包含如何解碼及驗證 ID 權杖回應的詳細資料
expires_in 存取權杖的剩餘生命週期 (以秒為單位)
refresh_token 可用來取得新存取權杖的權杖。重新整理權杖的有效期限,直到使用者撤銷存取權為止
scope 針對已連結帳戶的登入用途,這個欄位的值一律會設為 openid
token_type 傳回的權杖類型。目前,這個欄位的值一律會設為 Bearer
回應範例
HTTP/1.1 200 OK
Content-type: application/json; charset=utf-8

{
  "access_token": "Google-access-token",
  "id_token": "Google-ID-token",
  "expires_in": 3599,
  "token_type": "Bearer",
  "scope": "openid",
  "refresh_token": "Google-refresh-token"
}


POST /oauth2/v4/token HTTP/1.1
Host: www.googleapis.com
Content-Type: application/x-www-form-urlencoded

code=Google authorization code
&grant_type=authorization_code
&client_id=Google client id
&client_secret=Google client secret

驗證 ID 權杖回應

驗證並解碼JWT斷言

您可以使用針對您的語言JWT解碼庫來驗證和解碼JWT斷言。使用Google的JWKPEM格式的公鑰來驗證令牌的簽名。

解碼後,JWT斷言類似於以下示例:

{
  "sub": "1234567890",      // The unique ID of the user's Google Account
  "iss": "https://accounts.google.com",        // The assertion's issuer
  "aud": "123-abc.apps.googleusercontent.com", // Your server's client ID
  "iat": 233366400,         // Unix timestamp of the assertion's creation time
  "exp": 233370000,         // Unix timestamp of the assertion's expiration time
  "name": "Jan Jansen",
  "given_name": "Jan",
  "family_name": "Jansen",
  "email": "jan@gmail.com", // If present, the user's email address
  "email_verified": true,   // true, if Google has verified the email address
  "hd": "example.com",      // If present, the host domain of the user's GSuite email address
                            // If present, a URL to user's profile picture
  "picture": "https://lh3.googleusercontent.com/a-/AOh14GjlTnZKHAeb94A-FmEbwZv7uJD986VOF1mJGb2YYQ",
  "locale": "en_US"         // User's locale, from browser or phone settings
}

除了驗證令牌的簽名外,還要驗證斷言的頒發者( iss字段)為https://accounts.google.com ,受眾( aud字段)是您分配的客戶端ID,並且令牌尚未過期( exp場地)。

使用emailemail_verifiedhd字段,您可以確定Google是否託管電子郵件地址並對其具有權威性。如果Google具有權威性,則當前已知該用戶為合法帳戶所有者,您可以跳過密碼或其他挑戰方法。否則,可以使用這些方法在鏈接之前驗證帳戶。

Google具有權威性的情況:

  • email後綴為@gmail.com ,這是一個Gmail帳戶。
  • email_verified為true並且設置了hd ,這是一個G Suite帳戶。

用戶可以在不使用Gmail或G Suite的情況下註冊Google帳戶。如果email不包含@gmail.com後綴,並且hd缺失,則Google不具有權威性,建議使用密碼或其他挑戰方法來驗證用戶。當Google在創建Google帳戶時最初驗證了用戶時, email_verfied也可能為true,但是此後第三方電子郵件帳戶的所有權可能已更改。