Use Spotify Sign In with Firebase

Use Spotify Sign In with Firebase
https://github.com/firebase/functions-samples/tree/master/spotify-auth
をやってみた

## 環境
- Windows10
- PowerShell
- Visual Studio Code

## 作業フォルダ作成
適当な場所にgithubの内容をコピー

https://github.com/firebase/functions-samples

## Cloud Functionsの初期化

> Prerequisites
To learn how to get started with Cloud Functions for Firebase by having a look at our Getting Started Guide, trying the quickstart samples and looking at the documentation.

まずこれ読めとあるのでやっていく
https://firebase.google.com/docs/functions/get-started

Firebaseでプロジェクトを作成した（割愛）

```powershell
PS C:\> npm install -g firebase-tools
PS C:\> firebase login
Already logged in as XXX
PS C:\> firebase init functions
```

この時に、Firebaseで作成したプロジェクトを選択する

> Enable Billing on your Firebase project by switching to the Blaze or Flame plan, this is currently needed to be able to perform HTTP requests to external services from a Cloud Function. See the pricing page for more details.

function で外部URLへリクエストを投げるため、ライセンスを変更する。

## Googleサービスアカウントの作成

https://firebase.google.com/docs/admin/setup#add_firebase_to_your_app

> サービス アカウント用の秘密鍵ファイルを生成するには:
>  1.Firebase コンソールで、[設定] > [サービス アカウント] を開きます。
>  2.[新しい秘密鍵の生成] をクリックし、[キーを生成] をクリックして確定します。
>  3.キーを含む JSON ファイルを安全に保管します。

ダウンロードしたJSONファイルを`./functions/service-account.json`に保存する

## Spotify側でアプリ登録

> Create a Spotify app in the Spotify Developers website.

登録する

> Add the URL https://<application-id>.firebaseapp.com/popup.html to the Redirect URIs of your Spotify app.

このタイミングでは何のことかわからなかったので、適当に登録する

> Copy the Client ID and Client Secret of your Spotify app and use them to set the spotify.client_id and spotify.client_secret Google Cloud environment variables. For this use:

クライアントID、クライアントシークレットを取得して、firebaseに登録する

```powershell
PS C:\> firebase functions:config:set spotify.client_id="XXX" spotify.client_secret="XXX"
+  Functions config updated.

Please deploy your functions for the change to take effect by running firebase deploy --only functions
```

## Deploy 

上で、`firebase deploy --only functions`と出たのでやる

```powershell
PS C:\> firebase deploy --only functions

=== Deploying to 'xxx-xxx'...

i  deploying functions
Running command: npm --prefix "$RESOURCE_DIR" run lint

> xxx-functions@ lint C:\xxx\functions
> eslint --max-warnings=0 .

+  functions: Finished running predeploy script.
i  functions: ensuring required API cloudfunctions.googleapis.com is enabled...
+  functions: required API cloudfunctions.googleapis.com is enabled
i  functions: preparing functions directory for uploading...
i  functions: packaged functions (47.52 KB) for uploading
+  functions: functions folder uploaded successfully
i  functions: creating Node.js 8 function redirect(us-central1)...
i  functions: creating Node.js 8 function token(us-central1)...
+  functions[redirect(us-central1)]: Successful create operation. 
Function URL (redirect): https://us-central1-xxx.cloudfunctions.net/redirect
+  functions[token(us-central1)]: Successful create operation. 
Function URL (token): https://us-central1-xxx.cloudfunctions.net/token

+  Deploy complete!

Project Console: https://console.firebase.google.com/project/xxx/overview
```

??? 何が起きたかよくわからなかった。

> Run firebase deploy to effectively deploy the sample. The first time the Functions are deployed the process can take several minutes.

とあったので、今度は、`firebase deploy`を実行する。
→エラー、firebase databaseあたりのエラー

firebase WEBコンソールから、firebase database を有効にする

`firebase deploy`を再実行する

```powershell
PS C:\> firebase deploy

=== Deploying to 'xxx-xxx'...

i  deploying database, functions, hosting
Running command: npm --prefix "$RESOURCE_DIR" run lint

> xxx-functions@ lint C:\xxx\functions
> eslint --max-warnings=0 .

+  functions: Finished running predeploy script.
i  database: checking rules syntax...
+  database: rules syntax for database xxx-xxx is valid
i  functions: ensuring required API cloudfunctions.googleapis.com is enabled...
+  functions: required API cloudfunctions.googleapis.com is enabled
i  functions: preparing functions directory for uploading...
i  functions: packaged functions (47.52 KB) for uploading
+  functions: functions folder uploaded successfully
i  hosting[xxx-xxx]: beginning deploy...
i  hosting[xxx-xxx]: found 6 files in public
+  hosting[xxx-xxx]: file upload complete
i  database: releasing rules...
+  database: rules for database xxx-xxx released successfully
i  functions: updating Node.js 8 function redirect(us-central1)...
i  functions: updating Node.js 8 function token(us-central1)...
+  functions[redirect(us-central1)]: Successful update operation.
+  functions[token(us-central1)]: Successful update operation.
i  hosting[xxx-xxx]: finalizing version...
+  hosting[xxx-xxx]: version finalized
i  hosting[xxx-xxx]: releasing new version...
+  hosting[xxx-xxx]: release complete

+  Deploy complete!

Project Console: https://console.firebase.google.com/project/xxx-xxx/overview
Hosting URL: https://xxx-xxx.web.app
```

## 動作確認　１
`https://xxx-xxx.web.app`にアクセスしてみる。表示される。
Spotifyでログインする。エラーで止まる。。。
エラー内容

```
TypeError: Cannot read property 'url' of undefined
    at Spotify.getMe (/srv/index.js:88:59)
```

spotify APIを実行した結果を処理する部分でエラーが発生している様子
https://developer.spotify.com/console/get-current-user/

spotifyでAPIを実行して、結果が確認できる（上のURLで）ので、内容を確認すると、imagesがカラ

```
"images": [],
```

しかし、コード部分の記述はこう

```js:index.js
const profilePic = userResults.body['images'][0]['url'];
```

なのでこうした。
未定義の場合をカラ文字とした場合、別の場所でエラーが発生したので、画像のURLを適当に充てることにした

```js:index.js
const profilePic = userResults.body['images'][0] ? userResults.body['images'][0]['url'] : 'https://placehold.jp/50x50.png';
```

これでエラーは出なくなった。
しかし、ログイン済みの画面に切り替わらない。。。

## 動作確認　2

ログイン済みの画面に切り替わらない問題の解決

firebase hostingでは、二つのホスト名が割り当てられます

- プロジェクト名.web.app
- プロジェクト名.firebaseapp.com

どちらのホスト名でも動作するのですが、デプロイ後に表示されるメッセージは、`https://xxx-xxx.web.app`となっており、そのホスト名で動作確認を行っていたことが原因でした。
Spotify側に登録したリダイレクトURIと同じホスト名を使って動作確認する必要がありました。
（おそらくCookieの影響範囲あたりの問題だったと思う）

## 動作確認　3

ログアウト。

Firebase側のアプリのログアウトはできました。
再度ログインでSpotifyへリダイレクトされると、Spotiry側はログイン済みで、Firebase側へ戻ってきました。

OAuthの手続きとしてはそういうものかなーと、今のところ思ってます。