簡化 OAuth 和 Google 登入機制的連結程序

總覽

以 OAuth 為基礎的 Google 登入簡化連結功能除了加入 Google 登入外, OAuth 連結。這樣就能順暢連結 Google 使用者並可建立帳戶,讓使用者透過自己的 Google 帳戶在您的服務中建立新帳戶。

如要使用 OAuth 和 Google 登入功能進行帳戶連結,請遵循下列一般做法 步驟:

  1. 請先徵得使用者同意,允許存取自己的 Google 個人資料。
  2. 使用設定檔中的資訊檢查使用者帳戶是否存在。
  3. 如果是現有使用者,請連結這些帳戶。
  4. 如果在驗證系統中找不到對應的 Google 使用者, 驗證從 Google 收到的 ID 權杖。接著您可以根據需求建立使用者 儲存在 ID 權杖所含設定檔資訊上
這張圖顯示使用者透過簡化的連結流程來連結 Google 帳戶的步驟。第一張螢幕截圖顯示使用者該如何選取要連結的應用程式。第二個螢幕截圖可讓使用者確認他們是否已使用你的服務帳戶。第三張螢幕截圖可讓使用者選取要連結的 Google 帳戶。第四個螢幕截圖顯示將 Google 帳戶與您的應用程式連結的確認畫面。第五張螢幕截圖顯示 Google 應用程式中成功連結的使用者帳戶。

圖 1. 透過簡化連結程序在使用者手機上進行帳戶連結

精簡連結規定

,瞭解如何調查及移除這項存取權。

實作 OAuth 伺服器

您的權杖交換端點必須支援 checkcreateget 意圖。下方顯示完成帳戶連結流程的步驟,並指出呼叫不同意圖的時機:

  1. 使用者是否在驗證系統中擁有帳戶?(使用者選取「是」或「否」)
    1. 是:使用者是否使用與其 Google 帳戶相關聯的電子郵件地址登入平台?(使用者選取「是」或「否」)
      1. 是 :使用者是否在驗證系統中擁有相符的帳戶?(呼叫 check intent 以確認)
        1. 是:系統會呼叫 get intent,如果成功傳回意圖,就會連結帳戶。
        2. 否 :建立新帳戶?(使用者選取「是」或「否」)
          1. 是:系統會呼叫 create intent,如果建立意圖成功傳回,就會連結帳戶。
          2. 否 :系統會觸發網路 OAuth 流程、將使用者導向瀏覽器,並提供使用者其他電子郵件的連結選項。
      2. 否:系統會觸發網路 OAuth 流程、將使用者導向瀏覽器,並提供其他電子郵件的連結選項。
    2. 否 :使用者是否在驗證系統中擁有相符的帳戶?(呼叫 check intent 以確認)
      1. 是:系統會呼叫 get intent,如果成功傳回意圖,就會連結帳戶。
      2. 否:如果建立意圖成功傳回,系統會呼叫 create intent,並連結帳戶。

Check for an existing user account (check intent)

After the user gives consent to access their Google profile, Google sends a request that contains a signed assertion of the Google user's identity. The assertion contains information that includes the user's Google Account ID, name, and email address. The token exchange endpoint configured for your project handles that request.

If the corresponding Google account is already present in your authentication system, your token exchange endpoint responds with account_found=true. If the Google account doesn't match an existing user, your token exchange endpoint returns an HTTP 404 Not Found error with account_found=false.

The request has the following form:

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

grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&intent=check&assertion=JWT&scope=SCOPES&client_id=GOOGLE_CLIENT_ID&client_secret=GOOGLE_CLIENT_SECRET

Your token exchange endpoint must be able to handle the following parameters:

Token endpoint parameters
intent For these requests, the value of this parameter is check.
grant_type The type of token being exchanged. For these requests, this parameter has the value urn:ietf:params:oauth:grant-type:jwt-bearer.
assertion A JSON Web Token (JWT) that provides a signed assertion of the Google user's identity. The JWT contains information that includes the user's Google Account ID, name, and email address.
client_id The client ID you assigned to Google.
client_secret The client secret you assigned to Google.

To respond to the check intent requests, your token exchange endpoint must perform the following steps:

  • Validate and decode the JWT assertion.
  • Check if the Google account is already present in your authentication system.
Validate and decode the JWT assertion

You can validate and decode the JWT assertion by using a JWT-decoding library for your language. Use Google's public keys, available in JWK or PEM formats, to verify the token's signature.

When decoded, the JWT assertion looks like the following example:

{
  "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
}

In addition to verifying the token's signature, verify that the assertion's issuer (iss field) is https://accounts.google.com, that the audience (aud field) is your assigned client ID, and that the token has not expired (exp field).

Using the email, email_verified and hd fields you can determine if Google hosts and is authoritative for an email address. In cases where Google is authoritative the user is currently known to be the legitimate account owner and you may skip password or other challenges methods. Otherwise, these methods can be used to verify the account prior to linking.

Cases where Google is authoritative:

  • email has a @gmail.com suffix, this is a Gmail account.
  • email_verified is true and hd is set, this is a G Suite account.

Users may register for Google Accounts without using Gmail or G Suite. When email does not contain a @gmail.com suffix and hd is absent Google is not authoritative and password or other challenge methods are recommended to verify the user. email_verified can also be true as Google initially verified the user when the Google account was created, however ownership of the third party email account may have since changed.

Check if the Google account is already present in your authentication system

Check whether either of the following conditions are true:

  • The Google Account ID, found in the assertion's sub field, is in your user database.
  • The email address in the assertion matches a user in your user database.

If either condition is true, the user has already signed up. In that case, return a response like the following:

HTTP/1.1 200 Success
Content-Type: application/json;charset=UTF-8

{
  "account_found":"true",
}

If neither the Google Account ID nor the email address specified in the assertion matches a user in your database, the user hasn't signed up yet. In this case, your token exchange endpoint needs to reply with a HTTP 404 error that specifies "account_found": "false", as in the following example:

HTTP/1.1 404 Not found
Content-Type: application/json;charset=UTF-8

{
  "account_found":"false",
}

Handle automatic linking (get intent)

After the user gives consent to access their Google profile, Google sends a request that contains a signed assertion of the Google user's identity. The assertion contains information that includes the user's Google Account ID, name, and email address. The token exchange endpoint configured for your project handles that request.

If the corresponding Google Account is already present in your authentication system, your token exchange endpoint returns a token for the user. If the Google Account doesn't match an existing user, your token exchange endpoint returns a linking_error error and optional login_hint.

The request has the following form:

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

grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&intent=get&assertion=JWT&scope=SCOPES&client_id=GOOGLE_CLIENT_ID&client_secret=GOOGLE_CLIENT_SECRET

Your token exchange endpoint must be able to handle the following parameters:

Token endpoint parameters
intent For these requests, the value of this parameter is get.
grant_type The type of token being exchanged. For these requests, this parameter has the value urn:ietf:params:oauth:grant-type:jwt-bearer.
assertion A JSON Web Token (JWT) that provides a signed assertion of the Google user's identity. The JWT contains information that includes the user's Google Account ID, name, and email address.
scope Optional: Any scopes that you've configured Google to request from users.
client_id The client ID you assigned to Google.
client_secret The client secret you assigned to Google.

To respond to the get intent requests, your token exchange endpoint must perform the following steps:

  • Validate and decode the JWT assertion.
  • Check if the Google account is already present in your authentication system.
Validate and decode the JWT assertion

You can validate and decode the JWT assertion by using a JWT-decoding library for your language. Use Google's public keys, available in JWK or PEM formats, to verify the token's signature.

When decoded, the JWT assertion looks like the following example:

{
  "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
}

In addition to verifying the token's signature, verify that the assertion's issuer (iss field) is https://accounts.google.com, that the audience (aud field) is your assigned client ID, and that the token has not expired (exp field).

Using the email, email_verified and hd fields you can determine if Google hosts and is authoritative for an email address. In cases where Google is authoritative the user is currently known to be the legitimate account owner and you may skip password or other challenges methods. Otherwise, these methods can be used to verify the account prior to linking.

Cases where Google is authoritative:

  • email has a @gmail.com suffix, this is a Gmail account.
  • email_verified is true and hd is set, this is a G Suite account.

Users may register for Google Accounts without using Gmail or G Suite. When email does not contain a @gmail.com suffix and hd is absent Google is not authoritative and password or other challenge methods are recommended to verify the user. email_verified can also be true as Google initially verified the user when the Google account was created, however ownership of the third party email account may have since changed.

Check if the Google account is already present in your authentication system

Check whether either of the following conditions are true:

  • The Google Account ID, found in the assertion's sub field, is in your user database.
  • The email address in the assertion matches a user in your user database.

If an account is found for the user, issue an access token and return the values in a JSON object in the body of your HTTPS response, like in the following example:

{
  "token_type": "Bearer",
  "access_token": "ACCESS_TOKEN",

  "expires_in": SECONDS_TO_EXPIRATION
}

In some cases, account linking based on ID token might fail for the user. If it does so for any reason, your token exchange endpoint needs to reply with a HTTP 401 error that specifies error=linking_error, as the following example shows:

HTTP/1.1 401 Unauthorized
Content-Type: application/json;charset=UTF-8

{
  "error":"linking_error",
  "login_hint":"foo@bar.com"
}

When Google receives a 401 error response with linking_error, Google sends the user to your authorization endpoint with login_hint as a parameter. The user completes account linking using the OAuth linking flow in their browser.

透過 Google 登入功能處理帳戶建立作業 (建立意圖)

當使用者需要在您的服務上建立帳戶時,Google 會提出要求 附加至指定 intent=create 的權杖交換端點。

這項要求的格式如下:

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

response_type=token&grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&scope=SCOPES&intent=create&assertion=JWT&client_id=GOOGLE_CLIENT_ID&client_secret=GOOGLE_CLIENT_SECRET

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

權杖端點參數
intent 在這些要求中,這個參數的值為 create
grant_type 要交換的權杖類型。對於這些要求,這個 參數值為 urn:ietf:params:oauth:grant-type:jwt-bearer
assertion JSON Web Token (JWT),提供已簽署 識別使用者的身分JWT 所含資訊包括使用者的 Google 帳戶 ID、名稱和電子郵件地址。
client_id 您指派給 Google 的用戶端 ID。
client_secret 您指派給 Google 的用戶端密鑰。

assertion 參數中的 JWT 包含使用者的 Google 帳戶 ID。 姓名和電子郵件地址;您可以在 課程中也會快速介紹 Memorystore 這是 Google Cloud 的全代管 Redis 服務

如要回應 create 意圖要求,您的權杖交換端點必須執行下列步驟:

  • 驗證並解碼 JWT 斷言。
  • 驗證使用者資訊並建立新帳戶。
Validate and decode the JWT assertion

You can validate and decode the JWT assertion by using a JWT-decoding library for your language. Use Google's public keys, available in JWK or PEM formats, to verify the token's signature.

When decoded, the JWT assertion looks like the following example:

{
  "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
}

In addition to verifying the token's signature, verify that the assertion's issuer (iss field) is https://accounts.google.com, that the audience (aud field) is your assigned client ID, and that the token has not expired (exp field).

Using the email, email_verified and hd fields you can determine if Google hosts and is authoritative for an email address. In cases where Google is authoritative the user is currently known to be the legitimate account owner and you may skip password or other challenges methods. Otherwise, these methods can be used to verify the account prior to linking.

Cases where Google is authoritative:

  • email has a @gmail.com suffix, this is a Gmail account.
  • email_verified is true and hd is set, this is a G Suite account.

Users may register for Google Accounts without using Gmail or G Suite. When email does not contain a @gmail.com suffix and hd is absent Google is not authoritative and password or other challenge methods are recommended to verify the user. email_verified can also be true as Google initially verified the user when the Google account was created, however ownership of the third party email account may have since changed.

驗證使用者資訊並建立新帳戶

確認是否符合下列任一條件:

  • 在聲明的「sub」欄位中,有 Google 帳戶 ID 代表您的使用者 資料庫
  • 斷言中的電子郵件地址與您使用者資料庫中的使用者相符。

只要符合任一條件,就會提示使用者連結現有帳戶 使用自己的 Google 帳戶。方法是回應要求,並傳回 HTTP 401 錯誤 指定 error=linking_error,並提供使用者的電子郵件地址做為 login_hint。以下是回應範例:

HTTP/1.1 401 Unauthorized
Content-Type: application/json;charset=UTF-8

{
  "error":"linking_error",
  "login_hint":"foo@bar.com"
}

當 Google 收到含有 linking_error 的 401 錯誤回應時, 將使用者傳送至您的授權端點,並以 login_hint 做為參數。 使用者在瀏覽器中使用 OAuth 連結流程完成帳戶連結。

如果兩個條件皆不成立,請以這些資訊建立新的使用者帳戶 使用這組 API新帳戶通常不會設定密碼。是 建議您在其他平台中加入 Google 登入功能,方便使用者 使用 Google 帳戶登入或者,您也可以 是否可以透過電子郵件將密碼復原流程的連結傳送給使用者,以便允許 使用者設定密碼以登入其他平台。

建立完畢後,請核發存取權杖 ,並傳回 JSON 物件中 也就是您的 HTTPS 回應內文,如以下範例所示:

{
  "token_type": "Bearer",
  "access_token": "ACCESS_TOKEN",

  "expires_in": SECONDS_TO_EXPIRATION
}

取得 Google API 用戶端 ID

在帳戶連結註冊程序期間,系統會要求您提供 Google API 用戶端 ID。

如要使用您在完成 OAuth 連結步驟時建立的專案取得 API 用戶端 ID,若要這樣做,請完成下列步驟:

  1. 開啟 Cloud Shell 的「Credentials」(憑證) 頁面, Google API 控制台
  2. 建立或選取 Google API 專案。

    如果專案沒有網頁應用程式類型的用戶端 ID,請按一下 建立憑證 >OAuth 用戶端 ID要建立。請務必附上 在「已授權的 JavaScript 來源」方塊中找出您網站的網域。當你在 本機測試或開發,您必須同時新增 http://localhost 和 將 http://localhost:<port_number> 設為「已授權的 JavaScript 來源」欄位。

驗證實作

You can validate your implementation by using the OAuth 2.0 Playground tool.

In the tool, do the following steps:

  1. Click Configuration to open the OAuth 2.0 Configuration window.
  2. In the OAuth flow field, select Client-side.
  3. In the OAuth Endpoints field, select Custom.
  4. Specify your OAuth 2.0 endpoint and the client ID you assigned to Google in the corresponding fields.
  5. In the Step 1 section, don't select any Google scopes. Instead, leave this field blank or type a scope valid for your server (or an arbitrary string if you don't use OAuth scopes). When you're done, click Authorize APIs.
  6. In the Step 2 and Step 3 sections, go through the OAuth 2.0 flow and verify that each step works as intended.

You can validate your implementation by using the Google Account Linking Demo tool.

In the tool, do the following steps:

  1. Click the Sign-in with Google button.
  2. Choose the account you'd like to link.
  3. Enter the service ID.
  4. Optionally enter one or more scopes that you will request access for.
  5. Click Start Demo.
  6. When prompted, confirm that you may consent and deny the linking request.
  7. Confirm that you are redirected to your platform.