Google Home に話しかけたユーザーのメールアドレスを取得する

# Google Home とは

話しかけるだけでいろいろできるスピーカー

![ダウンロード.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63018/acd9e29e-06e1-90a8-b69a-ce450b4d468a.jpeg)
これは Google Home mini （家電量販店でいただきました）

家電を操作するには対応した機器（リモコン含む）が必要なので、持て余している人は多いと思います。
わが家でも持て余していましたが、とあるきっかけでGoogle Home アプリを作ってみることにしました。

そもそもGoogle Home アプリを作れることを知らなかったので、調査ばかりなのは必然として、一番苦労したのはメールアドレスの取得でした。
**メールアドレスの取得には放置期間を含めて2カ月を要しました。**
3行でできたときは拍子抜けしましたが、一番苦労したところなので、これを記事にします。

作ったアプリを使えるようにするには googleの審査が必要で、3/19現在、4度目の申請が、たった今、落ちました:sob:


# 環境設定

actions on google（Google Home アプリ）

 - account linking あり


# Google Home のリクエスト

### メタ情報

- 開発モード
- Account Linkingあり
- textPayload = request.body

### request

```json:
{
  "textPayload": "Sending request with post data: {\"user\": ...}",
  "insertId": "1flz6t8ftbo7kj",
  "resource": {
    "type": "assistant_action",
    "labels": {
      "version_id": "",
      "project_id": "shopping-memo-4a18c",
      "action_id": "actions.intent.MAIN"
    }
  },
  "timestamp": "2021-03-19T01:28:20.634786801Z",
  "severity": "DEBUG",
  "labels": {
    "querystream": "GOOGLE_USER",
    "channel": "preview",
    "source": "AOG_REQUEST_RESPONSE"
  },
  "logName": "projects/shopping-memo-4a18c/logs/actions.googleapis.com%2Factions",
  "trace": "projects/284585213741/traces/ABwppHGlFcuPRBOzIfKa53eqbF_-h6ez8vm4xR7kfdiUeGF03yPfkDvsuc2AfSmh_BMJxygOveEja3YqTqL0Vn_BYA",
  "receiveTimestamp": "2021-03-19T01:28:20.994062139Z"
}

```

### textPayload
```json
{
  "user": {
    "accessToken": "(ry",
    "locale": "ja-JP",
    "idToken": "(ry",
    "userVerificationStatus": "VERIFIED"
  },
  "conversation": {"conversationId": "ABwppHGlFcuPRBOzIfKa53eqbF_-h6ez8vm4xR7kfdiUeGF03yPfkDvsuc2AfSmh_BMJxygOveEja3YqTqL0Vn_BYA","type": "NEW"},
  "inputs": [
    {
      "intent": "actions.intent.MAIN",
      "rawInputs": [{"inputType": "VOICE","query": "メモっちにつないで"}]
    }
],
  "surface": {"capabilities": [{"name": "actions.capability.MEDIA_RESPONSE_AUDIO"},{"name": "actions.capability.ACCOUNT_LINKING"},{"name": "actions.capability.SCREEN_OUTPUT"},{"name": "actions.capability.WEB_BROWSER"},{"name": "actions.capability.AUDIO_OUTPUT"}]},
  "isInSandbox": true,
  "availableSurfaces": [{"capabilities": [{"name": "actions.capability.WEB_BROWSER"},{"name": "actions.capability.AUDIO_OUTPUT"},{"name": "actions.capability.SCREEN_OUTPUT"}]}]
}

```

### Google Home のリクエスト確認方法

Actions on Google で作成したGoogle Homeアプリのログは、ログエクスプローラで確認できます。

Actions on Google: [https://console.actions.google.com/](https://console.actions.google.com/)
ログエクスプローラ: [https://console.cloud.google.com/logs](https://console.cloud.google.com/logs)

### 解説
account linking を設定しているため、Google Home の voice match 機能により、話しかけた時点でユーザーが特定されます。

`"userVerificationStatus": "VERIFIED"` ユーザーが特定されている状態
 

**Google Home 機器本体の識別子はありません。**これがあれば、ユーザー認証（account linking）も不要でした。リンクするシーンも広がると思います。


# ユーザー情報取得（メールアドレス）

### 取得方法

Google Home でvoice matchしたユーザーのメールアドレス取得方法は以下の通りです

```javascript:nodejs@firebase.functinos
const dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
  const jwt_decode = require("jwt-decode");
  let decoded = jwt_decode(request.body.originalDetectIntentRequest.payload.user.accessToken);
  console.log(decoded.email);
})
```

### 取得結果

```json:console.logの結果
{
  "iss": "https://accounts.google.com",
  "nbf": "1616148530",
  "aud": "284585213741-p8ki0mu9bomc7ohm1j2di2hk4o96jnen.apps.googleusercontent.com",
  "sub": "103727671058376154330",
  "email": "ctrlzr@gmail.com",
  "email_verified": "true",
  "name": "Ctrlz Ctrlz",
  "picture": "https://lh3.googleusercontent.com/a-/AOh14GiDB6hQOqS2xhRvbIh3V_cusk2lUy_M2M78nC3Gew=s96-c",
  "given_name": "Ctrlz",
  "family_name": "Ctrlz",
  "locale": "en-US",
  "iat": "1616148830",
  "exp": "1616152430",
  "jti": "5d37c00bb8dffe54595acde5ab602884f83130f4"
}

```


# 紆余曲折

googleアカウントのユーザー情報を取得する方法はいくつかありましたが、**voice matchでユーザーは特定できているのに、また認証するのはおかしい**、という感覚がありました。

OAuthを使うと「ＸＸＸが次の情報を取得しようとしています。」のようなメッセージが表示されるので、Google Homeとは相性が悪いです。
account linking だけでもユーザーのハードルが高いのに、さらにOAuthの確認を入れるのは~~めんどくさかった~~避けたいと考えました。

メールアドレスの取得は、予想通り再認証は必要ありませんでしたが、
![yosou2-2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63018/6e026b0a-b6c3-b96a-a639-568eddb72cab.gif)
という気分でした。達成感はありましたが、
![datta1-2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63018/b1c25af2-8fbc-62f4-7904-46a0e74298a6.gif)
という虚無感もありました。


# 参考

 [Implement Google Sign-In account linking](https://developers.google.com/assistant/identity/google-sign-in) 
[How to get email address with google access token?](https://stackoverflow.com/questions/49513485/how-to-get-email-address-with-google-access-token)
[Google assistant でGoogleのアカウントの情報を取得する #dialogflow](https://qiita.com/flatfisher/items/1f39de99728d8717c73b)
[node.js 上の nodemailer で OAuth 2.0 を使って gmail からメールを送る]
(https://gist.github.com/neguse11/bc09d86e7acbd6442cd4)
[Google People APIを使ってみる](https://qiita.com/howdy39/items/13bd27d8383966b33e07)
[IDトークンが分かれば OpenID Connect が分かる](https://qiita.com/TakahikoKawasaki/items/8f0e422c7edd2d220e06#64-jwt-%E3%82%AF%E3%83%AC%E3%83%BC%E3%83%A0)

かなりの遠回りをしましたが、この遠回りが、いつか最短の道になると信じて。
![mawarimichi1-2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63018/2b605c0a-3632-6a44-6241-2922cab7b77e.gif)