OAuth によるアカウント リンク

OAuth リンクタイプは、業界標準の OAuth 2.0 フローであるインプリミティブ フローと認可コードフローの 2 つをサポートしています。

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. アクション コンソールを開き、使用するプロジェクトを選択します。
  2. [Develop](開発)タブをクリックして、[Account linking](アカウント リンク)を選択します。
  3. [アカウントのリンク] の横にあるスイッチを有効にします。
  4. [Account creation](アカウントの作成)セクションで、[No, I only want to allow account creation on my website](いいえ、自分のウェブサイトでのアカウントの作成のみを許可します)を選択します。
  5. [Linking type](リンクタイプ)で、[OAuth] と [Authorization code](認可コード)を選択します。

  6. [クライアント情報] で、次の操作を行います。

    • [Actions to Google に発行するクライアント ID] に値を割り当てます。これは、Google からのリクエストを識別する値です。
    • Google がアクションに対して発行したクライアント ID の値をメモします。
    • 認可エンドポイントとトークン交換エンドポイントの URL を挿入します。
  1. [保存] をクリックします。

OAuth サーバーを実装する

OAuth 2.0 サーバーでの認可コードフローの実装は 2 つのエンドポイントで構成され、お客様のサービスでは HTTPS でこれらのエンドポイントを利用できるようにします。最初のエンドポイントは認可エンドポイントで、データアクセスについてユーザーの同意を得る、またはユーザーからの同意を取得する役割を担います。認可エンドポイントは、ログインしていないユーザーにログイン用の UI を表示し、リクエストされたアクセスへの同意を記録します。2 つ目のエンドポイントはトークン交換エンドポイントで、トークンという暗号化された文字列を取得し、アクションのユーザーにサービスへのアクセスを許可します。

アクションでサービスの API を呼び出す必要がある場合、Google はこれらのエンドポイントを使用して、API の呼び出し許可をユーザーから取得します。

Google が開始する OAuth 2.0 認可コードフローのセッションは次のような流れになります。

  1. Google がユーザーのブラウザで認可エンドポイントを開きます。音声専用デバイスでアクションのフローが開始された場合、Google は実行をスマートフォンに転送します。
  2. ユーザーがログインし(ログインしていない場合)、Google が API を使用してデータにアクセスすることを承諾します(まだ許可していない場合)。

  3. サービスが認可コードを作成し、リクエストに付加された認可コードとともにユーザーのブラウザを Google にリダイレクトして Google に認可コードを返します。

  4. Google が認可コードをトークン交換エンドポイントに送信します。このエンドポイントはコードの真正性を検証し、アクセス トークン更新トークンを返します。アクセス トークンは有効期間の短いトークンで、サービスが API にアクセスするための認証情報として受け入れられます。更新トークンは長期間有効なトークンです。Google では、このトークンを保存して、有効期限が切れたときに新しいアクセス トークンを取得するために使用できます。

  5. ユーザーがアカウントのリンクのフローを完了すると、アシスタントからフルフィルメント Webhook に送信されるすべてのリクエストにアクセス トークンが含まれます。

認可リクエストの処理

アクションが OAuth 2.0 認可コードフローを介してアカウント リンクを実行する必要がある場合、Google は以下のパラメータを含むリクエストを使用して、ユーザーを認可エンドポイントに送信します。

認可エンドポイントのパラメータ
client_id Google に登録した Google クライアント ID。
redirect_uri このリクエストに対するレスポンスを送信する URL。
state リダイレクト URL で変更されずに Google に返される会計上の値。
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 が Google からご利用のサービス用に提供されたリダイレクト URL と一致することを確認します。このチェックは、意図しないクライアント アプリや誤って構成されたクライアント アプリへのアクセス許可を防ぐために重要です。

    複数の OAuth 2.0 フローをサポートしている場合は、response_typecode であることも確認してください。

  2. ユーザーがサービスにログインしているかどうか確認します。ユーザーがログインしていない場合は、サービスのログインまたは登録フローを完了します。

  3. Google が API へのアクセスに使用する認証コードを生成します。 認証コードには任意の文字列値を使用できますが、ユーザー、トークンを使用するクライアント、コードの有効期限を一意に表している必要があります。また、推測できない値は使用できません。通常、約 10 分後に期限切れになる認可コードを発行します。

  4. redirect_uri パラメータで指定された URL の形式が

    https://oauth-redirect.googleusercontent.com/r/YOUR_PROJECT_ID
    YOUR_PROJECT_ID の ID です。この ID は、Actions Console の [プロジェクトの設定] ページで確認できます。

  5. redirect_uri パラメータで指定された URL にユーザーのブラウザをリダイレクトします。code パラメータと state パラメータを追加してリダイレクトする場合は、生成した認証コードと、変更前の元の状態値を含めます。生成される URL は

    https://oauth-redirect.googleusercontent.com/r/YOUR_PROJECT_ID?code=AUTHORIZATION_CODE&state=STATE_STRING
    の例です。

トークン交換リクエストの処理

サービスのトークン交換エンドポイントは、次の 2 種類のトークン交換を処理します。

  • 認可コードとアクセス トークンおよび更新トークンとの交換
  • 更新トークンとアクセス トークンの交換

トークン交換リクエストには、次のパラメータを使用します。

トークン交換エンドポイントのパラメータ
client_id リクエスト元を Google として識別する文字列。この文字列は、Google の一意の識別子としてシステムに登録されている必要があります。
client_secret Google に登録したサービスのシークレット文字列。
grant_type 交換されるトークンの種類。authorization_code または refresh_token
code grant_type=authorization_code の場合、Google がログインまたはトークン交換エンドポイントから受け取ったコード。
redirect_uri grant_type=authorization_code の場合、このパラメータは最初の承認リクエストで使用される URL です。
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 パラメータで指定された URL は、最初の認可リクエストに使用された値と同じです。
  3. 上記の基準をすべて確認できない場合は、本文として {"error": "invalid_grant"} を含む HTTP 400 Bad Request エラーを返します。
  4. それ以外の場合は、認可コードのユーザー ID を使用して、更新トークンとアクセス トークンを生成します。これらのトークンには任意の文字列値を設定できますが、トークンを使用するユーザーとクライアントを一意に表し、簡単に推測されない文字列にする必要があります。アクセス トークンには、トークンの有効期限(通常はトークンを発行してから 1 時間)も記録します。更新トークンに有効期限はありません。
  5. HTTPS レスポンスの本文で次の JSON オブジェクトを返します。
    {
    "token_type": "Bearer",
    "access_token": "ACCESS_TOKEN",
    "refresh_token": "REFRESH_TOKEN",
    "expires_in": SECONDS_TO_EXPIRATION
    }
    

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. 上記の基準をすべて確認できない場合は、本文として {"error": "invalid_grant"} を含む HTTP 400 Bad Request エラーを返します。
  4. それ以外の場合は、更新トークンのユーザー ID を使用してアクセス トークンを生成します。これらのトークンには任意の文字列値を指定できますが、トークンを使用するユーザーとクライアントを一意に表す必要があり、推測可能な値であってはなりません。アクセス トークンの場合は、トークンの有効期限(通常はトークンを発行してから 1 時間)も記録します。
  5. HTTPS レスポンスの本文で次の JSON オブジェクトを返します。
    {
    "token_type": "Bearer",
    "access_token": "ACCESS_TOKEN",
    "expires_in": SECONDS_TO_EXPIRATION
    }

認証フローの音声ユーザー インターフェースを設計する

本人確認が完了しているかどうか確認してアカウントのリンクのフローを開始する

  1. Actions Console で Actions Builder プロジェクトを開きます。
  2. 新しいシーンを作成し、アクションでアカウントのリンクを開始します。
    1. [Scenes](シーン)をクリックします。
    2. 追加(+)アイコンをクリックして新しいシーンを追加します。
  3. 新しく作成したシーンで、[Conditions] の追加アイコン アイコンをクリックします。
  4. 会話に関連付けられたユーザーが確認済みユーザーかどうかを確認する条件を追加します。チェックが失敗した場合、アクションは会話中にアカウント リンクを実行できないため、アカウント リンクを必要としない機能にアクセスできるようにフォールバックする必要があります。
    1. [Condition] の Enter new expression フィールドに、次のロジックを入力します。 user.verificationStatus != "VERIFIED"
    2. [Transition] で、アカウントのリンクが不要なシーン、またはゲスト専用機能のエントリ ポイントとなるシーンを選択します。

  1. [Conditions] の追加アイコン をクリックします。
  2. ユーザーに ID が関連付けられていない場合に、アカウントのリンクのフローをトリガーする条件を追加します。
    1. [Condition] の Enter new expression フィールドに、次のロジックを入力します。 user.verificationStatus == "VERIFIED"
    2. [移行] で、[アカウントのリンク] システムシーンを選択します。
    3. [保存] をクリックします。

保存後、<SceneName>_AccountLinking という新しいアカウント リンク システムシーンがプロジェクトに追加されます。

アカウントのリンクのシーンをカスタマイズする

  1. [Scenes](シーン)で、アカウント リンクのシステムシーンを選択します。
  2. [プロンプトを送信] をクリックし、アクションが ID にアクセスする必要がある理由をユーザーに説明する短い文を追加します(「設定を保存するため」など)。
  3. [保存] をクリックします。

  1. [条件] で [ユーザーがアカウントのリンクを正常に完了した場合] をクリックします。
  2. ユーザーがアカウントのリンクに同意した場合のフローの動作を設定します。 たとえば、Webhook を呼び出して必要なカスタム ビジネス ロジックを処理し、元のシーンに戻ります。
  3. [保存] をクリックします。

  1. [条件] で、[ユーザーがアカウントのリンクをキャンセルまたは拒否した場合] をクリックします。
  2. ユーザーがアカウントのリンクに同意しなかった場合にフローがどのように進むかを構成します。たとえば、確認応答メッセージを送信し、アカウント リンクを必要としない機能を提供するシーンにリダイレクトします。
  3. [保存] をクリックします。

  1. [条件] で [システムエラーまたはネットワーク エラーが発生した場合] をクリックします。
  2. システムエラーまたはネットワーク エラーが原因でアカウント リンクのフローを完了できない場合のフローの構成。たとえば、確認応答メッセージを送信し、アカウント リンクを必要としない機能を提供するシーンにリダイレクトします。
  3. [保存] をクリックします。

データアクセス リクエストを処理する

アシスタントのリクエストにアクセス トークンが含まれている場合は、まずそのアクセス トークンが有効で期限切れになっていないことを確認してから、関連付けられているユーザー アカウントをデータベースから取得します。