Alexaのアカウントリンクをデバッグする方法

## 自己紹介
こんにちは，ZOZOテクノロジーズの内定者さっとです．
最近、Alexaアプリの開発で遊んでいます！
意外と簡単に開発できるので、身の回りがもっと便利になるようなスキルを開発したいと思うこの頃です。

※本記事は[ZOZOテクノロジーズ#5](https://qiita.com/advent-calendar/2019/zozo_tech5)の4日目です．
昨日は@pakioさんが「[v-for内のv-checkboxの値をwatchプロパティで検知したい](https://qiita.com/pakio/items/acf105fbd328840958e4)」という記事を出しました．
他にもZOZOテクノロジーズでは5つのアドベントカレンダーを毎日更新しています！

- [ZOZOテクノロジーズ#1](https://qiita.com/advent-calendar/2019/zozo_tech)
- [ZOZOテクノロジーズ#2](https://qiita.com/advent-calendar/2019/zozo_tech2)
- [ZOZOテクノロジーズ#3](https://qiita.com/advent-calendar/2019/zozo_tech3)
- [ZOZOテクノロジーズ#4](https://qiita.com/advent-calendar/2019/zozo_tech4)

## やること
アレクサアプリ開発でOAuth2.0を使った外部サービス（GoogleやFacebook，Slackなど）と連携したいことがあるかと思います．アレクサアプリでは，外部サービスとの連携を「アカウントリンク」と呼びますが，必要な項目を埋めるだけで簡単に設定することができます．

しかし，簡単に設定できるがゆえに，連携が失敗したり，上手くいかないとき調べる方法がありません．

そこで今回は，2016年にアレクサblogで紹介された下記の記事を元に，2019年版に刷新したデバック方法を紹介したいと思います．

[How to Set up Amazon API Gateway as a Proxy to Debug Account Linking](https://developer.amazon.com/ja/blogs/alexa/post/txqn2c04s97c0j/how-to-set-up-amazon-api-gateway-as-a-proxy-to-debug-account-linking)

## API Gatewayを用いたプロキシ
先のブログでは，下記のようにAlexaと外部サービスの間にAWSのAPI Gatewayを利用したHTTPプロキシを構築しています．

>![API Gateway_Image19._CB520207811_.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130670/6bac0a84-ea4c-e9c3-1f89-e24839f34765.jpeg)
> [How to Set up Amazon API Gateway as a Proxy to Debug Account Linking](https://developer.amazon.com/ja/blogs/alexa/post/txqn2c04s97c0j/how-to-set-up-amazon-api-gateway-as-a-proxy-to-debug-account-linking) より

このような構成にすることで，
Alexa Voice Serviceでアカウントリンクが実行されるときに発生するHTTPトラフィックはすべてCloudwatchに記録することができます．

## 環境構築
### 前提条件
今回は，連携する外部サービスとしてAmazonを利用します．
そのため，**Amazonのアカウント**が必要です．

また，AWSでHTTPプロキシを構築するため，**AWSアカウント**も別途必要です．
ここで注意したいのが，**IAMを作成できる権限**を持っていなければなりません．

### Login with Amazon
AmazonとAlexaを連携するためにLogin with AmazonにてOAuth2の証明書を作成しましょう．

作成した

* クライアントID
* クライアントシークレット

をメモしておきましょう．

Login with Amazonは下記からアクセスできます．
https://developer.amazon.com/loginwithamazon/console/site/lwa/overview.html

作成方法は，下記のAlexa Developers JPチャンネルの動画が参考になります．
また，アカウントリンク方法も紹介しているので，普通に神動画です．
https://youtu.be/dnzZzc2sKBA?t=960

### AWS CloudFormation
#### AWS CloudFormationとは
HTTPプロキシはAWSのCloudFormationを利用して作成します．
CloudFormationとは，AWSが提供するリソースのモデル化およびセットアップをサポートしてくれるサービスです．
API Gateway，Cloudwatchなどのリソースの構築に必要な設定を記述したテンプレートファイルをインポートすることで簡単に環境を構築することができます．

#### テンプレートのダウンロードと編集
今回は，[本家サイト](https://developer.amazon.com/ja/blogs/alexa/post/txqn2c04s97c0j/how-to-set-up-amazon-api-gateway-as-a-proxy-to-debug-account-linking)が提供するCloudFormationのテンプレートファイルを用いて構築するので事前にダウンロードしておきましょう．
> https://alexademo.ninja/httpproxy/cloudformation-us-east-1.json
> How to Set up Amazon API Gateway as a Proxy to Debug Account Linking より

また，ブログは2016年のもので，テンプレートもその当時のままです．
このままでは，ビルド時に下記のようなエラーが発生してしまいます．

```
The runtime parameter of nodejs4.3 is no longer supported for creating or updating AWS Lambda functions. We recommend you use the new runtime (nodejs8.10, nodejs10.x) while creating or updating functions. (Service: AWSLambdaInternal; Status Code: 400; Error Code: InvalidParameterValueException;)
```
エラーは，Lambda構築時にnodejsのバージョンが対応していないため，怒られています．
ログを見ると，nodejs8.10やnodejs10.xにしてと言われているので，下記のようにファイルを編集します．

65行目が```"Runtime": "nodejs4.3",```となっているので，
これを下記のように```"Runtime": "nodejs8.10",```に変更し，保存しましょう．

```json
    "HostnameLambda": {
      "Type": "AWS::Lambda::Function",
      "Properties": {
        "Code": {
          "S3Bucket": "alexademo.ninja",
          "S3Key": "httpproxy/lambda/hostname_lambda_function.zip"
        },
        "Handler": "index.handler",
        "Runtime": "nodejs8.10",
        "Timeout": "30",
        "Role": {
          "Fn::GetAtt": ["LambdaExecutionRole", "Arn"]
        }
      }
    },
```

#### サービスの選択
まず，リージョンを**バージニア北部**に設定しましょう．
その後，サービスから**CloudFormation**を選択します．
![Inked68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3133303637302f34626465393765372d643761322d363932372d623132612d3337626166386336643432342e706e67_LI.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130670/4fca61a0-890a-7182-5edf-91de39fcdc3f.jpeg)

#### スタックの作成
CloudFormationのスタックを作成します．
![Inkedtempsnip3_LI.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130670/bba2ce93-cf3f-3502-892c-fbaa48eb471f.jpeg)

#### テンプレートの選択
次に，**テンプレートファイルのアップロード**を選択し，
**ファイルの選択**でテンプレートファイルをアップデートします．
最後に，**次へ**を押します．
![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3133303637302f63336230373933342d353438622d656639322d623338312d6539343234366139393930312e706e67.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130670/244fb05a-38f1-d989-ba15-958d35f21810.png)


#### パラメータの設定
次に，**スタックの名前**を設定します．
これは，わかりやすい名前であれば何でも良いですが，今回は**OAuthDebug**としました．
その後，外部サービスと連携するために必要な**AccessTokenURL**と**AuthorizationURL**を設定しましょう．
今回は，Login with Amazonを利用するのでデフォルトで入っているとおりにします．

Login with Amazonの詳細なドキュメントは下記から確認してください．
https://developer.amazon.com/ja/docs/login-with-amazon/authorization-code-grant.html

![tempsnip5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130670/b1da00ac-2317-3caa-a1e4-1e41550533e2.png)

#### スタックオプションの設定および詳細オプション
ここは，特に設定する項目は無いので，**次へ**を選択します．

#### スタックの作成
最後に，IAMが作成されることを承認し，スタックを作成しましょう．
![tempsnip6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130670/7ea5623c-4cbf-41cd-8564-092b3348435d.png)

#### スタックの構築状況の確認
イベントログが流れ，環境が構築されている様子が見えると思います．

スタックの構築状況を確認するために，タブで**スタックの情報**を選択しましょう．
ステータスが**CREATE_COMPLETE**になるまで待ちます．
大体30秒~1分ぐらいかかります．
![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3133303637302f34663435613636632d353237372d333030372d666538372d3531383833383938363431352e6a706567.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130670/64859728-44dc-13ab-8334-433d5ebe926f.jpeg)


#### リンクのコピー

出力された**ProxyAccessTokenURL**と**ProxyAuthenticationURL**はプロキシの入り口となるリンクになります．

Alexa開発者コンソールのアカウントリンクにこれらのURLを設定することで，HTTPプロキシ経由で外部サービスと通信を行うことが可能になります．
![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3133303637302f63333465333837392d366538392d323435372d363233632d6236316566323837386138652e706e67.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130670/dbd650db-d96e-05db-b5b8-d37b0390d99a.png)


#### アレクサアプリの設定
Alexa開発者コンソールからリンクアカウントの設定を行います．
**ProxyAuthenticationURL**を**認証画面のURI**に貼り付けます
**ProxyAuthenticationURL**を**アクセストークンのURI**
![hoge.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130670/12b51dff-35a7-a2a6-595e-6f53e1854341.png)


## 実際に通信を発生させてみる

- スマホのアレクサアプリからデバックしたいスキルを選択しアカウントリンクをクリックします．

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130670/f1f31df4-0355-1cc9-c401-2e819bec65a1.jpeg" width=300 height=600>

- これはおなじみのOauth2.0の認証画面ですね．

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130670/311bb8cd-b61f-7d2d-9e2b-0eb655849ba0.jpeg" width=300 height=600>

- 認証が成功すると次の画面が表示されます．

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130670/4b7a8218-1ea2-cf29-5cfa-ece474ec2075.jpeg" width=300 height=600>

### デバックログの確認
- AWSのコンソールから**CloudWatch**のサービスを選択
- **ロググループ**を見ると**API-Gateway-Execution-Logs**が表示されていることがわかります．
![alexa2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130670/4c65a22e-f07b-e777-8047-687ee149baa0.png)


- ログストリームが２つあり，それぞれ**コード発行**および**トークン発行**時に発生したログになります．

![alexa3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130670/43151dba-e829-59a0-2c52-d3a47149de9e.png)

- ログを確認するとaccess_tokenもここで確認できます．

### 認証失敗時のログ

- デバックが機能しているかを確認するためにクライアントシークレットをあえて間違えてみます．

- 認証しようとすると勿論「アカウントリンクを完了できませんでした」と表示されます．
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130670/58a14e24-7894-9df8-ef7f-f6c89a6679fd.jpeg" width=300 height=600>

- このときのログを確認すると

コード発行は無事できていることがわかります．

```
Successfully completed execution
```

しかし，アクセストークン取得時に失敗していることが確認できます．

```
{
    "error_description": "Client authentication failed",
    "error": "invalid_client"
}
```

また，**イベントフィルター**でerrorと入れて検索するとエラーが起きているログだけ抽出できるので，
デバック作業の足がかりになると思います．
![alexa4.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130670/fa5b3baa-04f8-086e-a0fb-2ceb46f60051.png)


## おわりに
今回は，Alexaアプリでアカウントリンク失敗した際のデバック方法を紹介しました．

Alexaに限らず，似たようなサービスでも利用できますので，ぜひ利用してみてください．

明日は，@ikeponsu さんで「Go言語の標準パッケージだけで画像処理をする その１ （入出力）」です！
お楽しみに！