透過 OAuth 連結帳戶

OAuth 連結類型支援兩種符合業界標準的 OAuth 2.0 流程,分別是隱含授權程式碼流程。

In the implicit code flow, Google opens your authorization endpoint in the user's browser. After successful sign in, you return a long-lived access token to Google. This access token is now included in every request sent from the Assistant to your Action.

In the authorization code flow, you need two endpoints:

  • The authorization endpoint, which is responsible for presenting the sign-in UI to your users that aren't already signed in and recording consent to the requested access in the form of a short-lived authorization code.
  • The token exchange endpoint, which is responsible for two types of exchanges:
    1. Exchanges an authorization code for a long-lived refresh token and a short-lived access token. This exchange happens when the user goes through the account linking flow.
    2. Exchanges a long-lived refresh token for a short-lived access token. This exchange happens when Google needs a new access token because the one it had expired.

Although the implicit code flow is simpler to implement, Google recommends that access tokens issued using the implicit flow never expire, because using token expiration with the implicit flow forces the user to link their account again. If you need token expiration for security reasons, you should strongly consider using the auth code flow instead.

實作 OAuth 帳戶連結

設定專案

如要將專案設為使用 OAuth 連結,請按照下列步驟操作:

  1. 開啟「Actions Console」,然後選取要使用的專案。
  2. 按一下「開發」分頁標籤,然後選擇「帳戶連結」
  3. 啟用「帳戶連結」旁的切換鈕。
  4. 在「建立帳戶」部分中,選取「否,我只想允許在我的網站上建立帳戶」
  5. 在「連結類型」中,選取「OAuth」和「授權碼」

  6. 在「客戶資訊」部分中:

    • 將值指派給「Actions to Google」的用戶端 ID,即可識別來自 Google 的要求。
    • 記下「Google 核發給您動作的用戶端 ID」值;
    • 插入授權和權杖交換端點的網址。
  1. 點按「儲存」

實作 OAuth 伺服器

授權碼流程的 OAuth 2.0 伺服器實作包含兩個端點,您的服務透過 HTTPS 提供。第一個端點是授權端點,負責查找或取得使用者的同意聲明,取得資料存取權。授權端點會向尚未登入的使用者顯示登入使用者介面,並記錄同意所要求的存取權。第二個端點是權杖交換端點,用於取得加密字串 (稱為權杖),以授權動作使用者存取您的服務。

當動作需要呼叫您服務的其中一個 API 時,Google 會一起使用這些端點取得使用者的權限,讓他們代表使用者呼叫這些 API。

Google 發起的 OAuth 2.0 驗證碼流程工作階段如下:

  1. Google 會在使用者的瀏覽器中開啟授權端點。如果在純語音裝置上啟動動作的流程,Google 會將執行作業轉移至手機。
  2. 使用者登入 (如果尚未登入),並授權 Google 在尚未授予權限的情況下透過您的 API 存取其資料。

  3. 您的服務會建立授權碼,並透過將使用者的瀏覽器重新導向回 Google,並提供要求中附加的授權碼,藉此將授權碼傳回 Google。

  4. Google 會將授權碼傳送至您的權杖交換端點,此端點可驗證程式碼的真實性,並傳回存取權杖更新權杖。存取權杖是短期權杖,您的服務可以接受做為存取 API 的憑證。更新權杖是長效權杖,Google 可儲存及用於在新的存取權杖過期時取得該權杖。

  5. 使用者完成帳戶連結流程後,每個從 Google 助理傳送至執行要求 Webhook 的後續要求都會包含一個存取權杖。

處理授權要求

當您的動作需要透過 OAuth 2.0 授權碼流程執行帳戶連結時,Google 會透過包含下列參數的要求將使用者導向授權端點:

授權端點參數
client_id 您在 Google 註冊的 Google 用戶端 ID。
redirect_uri 您將回應傳送至此要求的網址。
state 傳遞至 Google 的簿記值在重新導向 URI 中維持不變。
scope 選用:以空格分隔的一組範圍字串,用於指定 Google 要求授權的資料。
response_type code 字串。

舉例來說,如果您在 https://myservice.example.com/auth 取得授權端點,要求看起來可能會像這樣:

GET https://myservice.example.com/auth?client_id=GOOGLE_CLIENT_ID&redirect_uri=REDIRECT_URI&state=STATE_STRING&scope=REQUESTED_SCOPES&response_type=code

如要讓授權端點處理登入要求,請按照下列步驟操作:

  1. 確認 client_id 與您註冊 Google 的 Google 用戶端 ID 相符,且 redirect_uri 與您為服務提供的重新導向網址相符。這些檢查至關重要,是防止系統授予意外或設定錯誤用戶端應用程式的存取權。

    如果您支援多個 OAuth 2.0 流程,請一併確認 response_typecode

  2. 檢查使用者是否已登入您的服務。如果使用者尚未登入,請完成服務的登入或註冊流程。

  3. 產生 Google 用來存取 API 的授權碼。授權碼可以是任何字串值,但它必須專門代表使用者、憑證用途的用戶端、代碼的到期時間,且不容易猜測。一般而言,核發的授權碼會在大約 10 分鐘後失效。

  4. 確認 redirect_uri 參數指定的網址格式如下:

    https://oauth-redirect.googleusercontent.com/r/YOUR_PROJECT_ID
    YOUR_PROJECT_ID 是 Actions Console「專案設定」頁面中的 ID。

  5. 將使用者的瀏覽器重新導向至 redirect_uri 參數指定的網址。請在重新導向時加上 codestate 參數,加入您剛產生的授權碼和原始未經修改的狀態值。以下是結果網址範例:

    https://oauth-redirect.googleusercontent.com/r/YOUR_PROJECT_ID?code=AUTHORIZATION_CODE&state=STATE_STRING

處理權杖交換要求

您的服務權杖交換端點會負責處理兩種權杖交換:

  • 交換存取權杖和更新權杖的授權碼
  • 交換存取權杖的更新權杖

權杖交換要求包含下列參數:

權杖交換端點參數
client_id 用來識別要求來源為 Google 的字串。這個字串必須在系統內註冊為 Google 的專屬 ID。
client_secret 你向 Google 註冊服務的機密字串。
grant_type 要交換的權杖類型。authorization_coderefresh_token
code 如果設為 grant_type=authorization_code,表示 Google 從您的登入或權杖交換端點收到的代碼。
redirect_uri 若為 grant_type=authorization_code,這個參數是初始授權要求中使用的網址。
refresh_token 設為 grant_type=refresh_token 時,Google 從權杖交換端點收到的更新權杖。
交換存取權杖和更新權杖的授權碼

使用者登入和授權端點將短期授權碼傳回 Google 後,Google 會向您的權杖交換端點傳送要求,以交換存取權杖和更新權杖的授權碼。

針對這些要求,grant_type 的值為 authorization_codecode 的值則是您先前授予 Google 的授權碼值。以下是要求交換存取權杖和更新權杖的授權碼的要求範例:

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

client_id=GOOGLE_CLIENT_ID&client_secret=GOOGLE_CLIENT_SECRET&grant_type=authorization_code&code=AUTHORIZATION_CODE&redirect_uri=REDIRECT_URI

如要交換存取權杖和更新權杖的授權碼,權杖交換端點會回應執行下列步驟的 POST 要求:

  1. 確認 client_id 會將要求來源識別為已授權來源,且 client_secret 符合預期值。
  2. 確認下列事項:
    • 授權碼有效且並未過期,而且要求中指定的用戶端 ID 與授權碼相關聯的用戶端 ID。
    • redirect_uri 參數指定的網址與初始授權要求中使用的值相同。
  3. 如果無法確認上述所有條件,就會傳回 HTTP 400 Bad Request 錯誤,且主體為 {"error": "invalid_grant"}
  4. 否則,請使用授權碼中的使用者 ID,並產生更新權杖和存取權杖。這些權杖可以是任何字串值,但權杖必須專門代表使用者和用戶端,且不得猜測。針對存取權杖,請一併記錄權杖的到期時間 (通常是發出權杖後的一小時)。重新整理權杖不會過期。
  5. 在 HTTPS 回應的主體中傳回下列 JSON 物件:
    {
    "token_type": "Bearer",
    "access_token": "ACCESS_TOKEN",
    "refresh_token": "REFRESH_TOKEN",
    "expires_in": SECONDS_TO_EXPIRATION
    }
    

Google 會儲存使用者的存取權杖和更新權杖,並記錄存取權杖的到期時間。存取權杖過期後,Google 會使用更新權杖從權杖交換端點取得新的存取權杖。

交換存取權杖的更新權杖

存取權杖過期時,Google 會向您的權杖交換端點傳送要求,以交換更新權杖來取得新的存取權杖。

針對這些要求,grant_type 的值為 refresh_tokenrefresh_token 的值則是您先前授予 Google 的更新權杖值。以下舉例說明如何將更新權杖交換為存取權杖:

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

client_id=GOOGLE_CLIENT_ID&client_secret=GOOGLE_CLIENT_SECRET&grant_type=refresh_token&refresh_token=REFRESH_TOKEN

如要交換存取權杖的更新權杖,權杖交換端點會回應 POST 要求,請執行下列步驟:

  1. 確認 client_id 會將要求來源識別為 Google,且 client_secret 符合預期值。
  2. 驗證更新權杖是否有效,且要求中指定的用戶端 ID 與與更新憑證相關聯的用戶端 ID 相符。
  3. 如果無法確認上述所有條件,就會傳回 HTTP 400 Bad Request 錯誤,且主體為 {"error": "invalid_grant"}
  4. 否則,請使用更新憑證中的使用者 ID 產生存取權杖。這些權杖可以是任何字串值,但權杖必須專門代表使用者和用戶端,且不得猜測。針對存取權杖,請一併記錄權杖的到期時間 (通常是發出權杖後的一小時)。
  5. 在 HTTPS 回應的主體中傳回下列 JSON 物件:
    {
    "token_type": "Bearer",
    "access_token": "ACCESS_TOKEN",
    "expires_in": SECONDS_TO_EXPIRATION
    }

設計驗證流程的語音使用者介面

檢查使用者是否已通過驗證,並啟動帳戶連結流程

  1. Actions 主控台中開啟 Actions Builder 專案。
  2. 建立新的場景,以便在動作中開始連結帳戶:
    1. 按一下「Scenes」
    2. 按一下「add」圖示 (+) 即可新增場景。
  3. 在新建立的場景中,按一下「Conditions」(條件) 圖示
  4. 新增條件,檢查與對話相關聯的使用者是否為已驗證的使用者。如果檢查失敗,您的動作就無法在對話期間執行帳戶連結,而是應改回提供不需要帳戶連結的功能。
    1. 在「Condition」(條件) 下方的 Enter new expression 欄位中,輸入下列邏輯:user.verificationStatus != "VERIFIED"
    2. 在「轉換」下方,選取不需要連結帳戶的場景,或不需要訪客專屬功能的進入點。

  1. 按一下「條件」的「新增」圖示
  2. 新增條件,在使用者沒有相關聯的身分時觸發帳戶連結流程。
    1. 在「Condition」(條件) 下方的 Enter new expression 欄位中,輸入下列邏輯:user.verificationStatus == "VERIFIED"
    2. 在「轉換」下方,選取「帳戶連結」系統場景。
    3. 點按「儲存」

儲存後,名為 <SceneName>_AccountLinking 的帳戶連結系統場景就會新增至專案中。

自訂帳戶連結情境

  1. 在「場景」下方,選取帳戶連結系統場景。
  2. 按一下「Send 提示」,然後新增簡短句子,說明動作需要存取其身分的原因 (例如「如要儲存偏好設定」)。
  3. 點按「儲存」

  1. 在「條件」下方,按一下「如果使用者成功完成帳戶連結」
  2. 設定使用者同意連結帳戶時,流程的後續步驟。 舉例來說,呼叫 Webhook 以處理任何所需的自訂商業邏輯,然後切換回原始場景。
  3. 點按「儲存」

  1. 在「條件」下方,按一下「如果使用者取消或關閉帳戶連結」
  2. 如果使用者不同意連結帳戶,請設定流程。例如,傳送已確認的訊息,然後重新導向至提供不需要連結帳戶的功能的場景。
  3. 點按「儲存」

  1. 在「條件」下方,按一下「如果發生系統或網路錯誤」
  2. 設定若帳戶連結流程因系統或網路錯誤而無法順利完成時,流程該如何繼續。 例如,傳送已確認的訊息,然後重新導向至提供不需要連結帳戶的功能的場景。
  3. 點按「儲存」

處理資料存取要求

如果 Google 助理要求包含存取權杖,請先檢查存取權杖是否有效 (且未過期),然後從資料庫中擷取相關聯的使用者帳戶。