ReactとAmplifyでCognitoとgoogleサインイン/サインナップ試してみた

一通り設定内容を把握したかったので、マニュアルで設定してみた記録です。先に感想ですが、サードパーティーのログイン機構が簡単に実装でき、だいぶ強力なサービスでした。

参考にしたページは、以下になります。
https://aws-amplify.github.io/docs/js/authentication

# CognitoとGoogle APIsの設定

## Mange User Pools

[ユーザープールにアクセス](https://ap-northeast-1.console.aws.amazon.com/cognito/users/?region=ap-northeast-1#)します。
<img width="330" alt="ユーザープールにアクセス" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18766/e3452fe6-42d1-ee2d-1102-b9af23907cca.png" />

*Create a user pool*をクリックします。
<img width="330" alt="Create a user poolをクリック" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18766/fc83dbb0-18a2-0fde-34db-cce11b569d57.png" />

*Pool name*を指定します。Pool nameは再設定ができない様なので、名前を決める時はよく考えて決めたほうが良いです。
<img width="330" alt="Pool nameを指定" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18766/1850180c-d894-24fe-3d8c-0c2b565ed20e.png" />

*Review defaults*を選択します。
<img width="330" alt="Review defaultsを指定" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18766/a685ec63-36cb-dde3-ea4f-57f83b14e330.png" />

Review画面
<img width="330" alt="Review画面" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18766/d49c3719-6abe-bfe2-40a4-6e892a17882d.png" />

Attributesを設定します。一度設定すると再設定できないようなので、扱う情報をどうするか事前に考える必要があります。
<img width="330" alt="Attributesを設定" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18766/986845d2-a814-bd20-b9bb-7fe67976eca1.png" />

今回は、Emailアドレスとユーザー名でサインインできるようにします。*Standard attributes*は、ログインに使用するものだけ指定します。必要に応じて変更するとよいと思いますが、最初に決める必があります。*Custom attribe*（後で新たに追加）もできるようなので、この辺りは慎重に考えて決めたほうが良いでしょう。
<img width="330" alt="Attributesを設定" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18766/f4a1d01e-8943-dd4d-1c86-d642d8d22299.png" />

パスワードの強さの設定や*Policies*で、管理者のみ追加権限指定で、任意のユーザー登録を無効にできます。
<img width="330" alt="Attributesを設定" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18766/dfe80b28-6c40-6d6e-bf8e-6746227e2112.png" />

後、MFAの設定などありますが、必要に応じて設定ができるのでスルーします。

最後に、*App Clients*の設定をします。
<img width="330" alt="App Clientsの設定" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18766/b7b0a124-617c-88cb-4297-86de8d3ac326.png" />

Webのみで認証するので、以下の設定にします。
<img width="330" alt="App Clientsの設定1" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18766/43aee445-4485-86e5-abf9-5e4d26cec5e1.png" />

App Clientsが作成されると、*App Client Id*が発行されます。このIdは、後ほど使います。
<img width="330" alt="App Clientsの設定2" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18766/27f8fb62-3939-9ea4-bae6-d983bfe69abf.png" />

作成完了します。ここで生成された**Pool Id**は、後ほど使います。
<img width="330" alt="Cognito User Pool 設定完了" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18766/e976bf07-1eb9-810a-1852-7a7af1ecebe0.png" />

## Manage Federated Identities
[Federated Identitiesをクリック](https://console.aws.amazon.com/cognito/create)します。

<img width="330" alt="Manage Federated Identities" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18766/183eb59b-3a79-9a50-95ae-c35982b3a0f3.png" />

*Pool name*を指定して、*Authentication providers*を開き、赤く囲ったcognitoの設定項目に、先程作成した、User Pool IdとApp Client Idを指定します。そして、作成を押して進みます。
<img width="330" alt="Identity poolの作成" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18766/48b2b2f9-d32b-10d3-580e-f86f2ad8a2d4.png" />

最後に、*Identity Pool Id*が表示されるます。これも後ほど使いますので、記録してください。
<img width="330" alt="Identity poolの作成" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18766/5e8246ef-fecb-0c0d-a474-3eb513db366a.png" />

Identity Pool Idは、*Edit Identity Pool*から確認できます。
<img width="330" alt="Identity poolの作成" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18766/f5005b2b-3d63-9bbf-6211-372c9c6b7c37.png" />

## Google APIsの設定
User PoolのIdのプロバイダーにGoogleも使うので、その設定をします。

[Google Cloud Platform](https://console.cloud.google.com/)にアクセスして、

**メニュー　&gt; APIs & Services &gt; Credentials**

にアクセスします。
<img width="330" alt="GCP APIs" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18766/b2d17a5c-087e-b2b6-d144-c298a4dbbc42.png" />

**Create Credentials**を押します。
<img width="330" alt="GCP APIs" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18766/6517217a-18d9-87b1-751a-c7a42d15d884.png" />

OAuth client IDを選択します。
<img width="330" alt="GCP APIs　OAuth client ID" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18766/0ee9caef-0003-afb2-2936-e4affc0f1da1.png" />

**Web application**を選択し、Restrictionsを以下の様に設定します。
<img width="330" alt="GCP APIs OAuth client ID" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18766/326411ec-48d4-3a77-adbf-9a8d4fc61f36.png" />

Authorized JavaScript origins.

```
https://<your-user-pool-domain>
```

Authorized Redirect URIs.

```
https://<your-user-pool-domain>/oauth2/idpresponse
```

詳細はこちらにあります。
https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-social-idp.html


*Your Client ID*をプロバイダーGoogleの設定項目に設定します。
<img width="330" alt="GCP APIs　OAuth client ID" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18766/859fd49b-7c8e-2061-f097-3f3a9fdd220e.png" />

**Federated IdentitiesUser Pools &gt; Edit identity pool**へ移動します。Unlockして*Your Client ID*を入力して保存します。
<img width="330" alt="GCP APIs OAuth client ID Google Provider" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18766/b943236a-a5c0-d4c3-7e74-aeb558328bc2.png" />

後から確認もできます。
OAuth 2.0 Client IDs
<img width="330" alt="GCP APIs OAuth ID & Secret" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18766/3e59de68-a837-da2e-d38c-a77a884a46a6.png" />

赤丸囲いクリックして詳細を確認できます。
<img width="330" alt="GCP APIs OAuth ID & Secret" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18766/4a542a3d-d3f8-24c7-fb78-442c4be2a992.png" />

## Reactで使う情報まとめ
*UserPoolId*
User Pool作成時に生成されたIDで、フォーマットは見た目は、

`ap-northeast-1_*******`な感じ


*IdentityPoolId*
Identity Pool作成時に生成されたIDで、フォーマットは見た目は、

`ap-northeast-1:********-****-****-****-************`な感じ


* ClientId: 
App Client作成時に生成されたIDで、フォーマットは見た目は、

`7nq7sou3kac74bkfuoee92nes33`な感じ

* Google Client Id:
Google APIsで作成されたIDで、フォーマットの見た目は、

`********-************************.apps.googleusercontent.com`な感じ

# Reactでサインイン/サインナップ

## Reactの準備
今回はMacOSを使います。コンソールを開き、開発用のディレクトリを作成しそこに移動します。

### npmの準備
```bash
$ mkdir workingdir
$ cd workingdir/
$ brew install npm
$ npm install -g n
$ n stable  # ローカルのnode_modulesを参照する
$ npm install -g yarn
```

### バージョン確認
```bash
$ npm -v
6.13.6
$ node -v
v12.15.0
```

### Reactをインストール
```bash
$ npm install react
```

### Reactアプリを作成
```bash
$ npx create-react-app my-app --template typescript
$ tree -I node_modules -L 2 my-app/
my-app/  # 以下のようなディレクトリが作成されます(node_modulesは省いてます)
├── README.md
├── package-lock.json
├── package.json
├── public
│   ├── favicon.ico
│   ├── index.html
│   ├── logo192.png
│   ├── logo512.png
│   ├── manifest.json
│   └── robots.txt
├── src
│   ├── App.css
│   ├── App.test.tsx
│   ├── App.tsx
│   ├── index.css
│   ├── index.tsx
│   ├── logo.svg
│   ├── react-app-env.d.ts
│   ├── serviceWorker.ts
│   └── setupTests.ts
└── tsconfig.json
$ cd my-app
$ yarn add amazon-cognito-identity-js  # cognitoを使うためのモジュールを入れておく
$ npm start
Compiled successfully!

You can now view app in the browser.

  Local:            http://localhost:3000/
  On Your Network:  http://192.168.***.***:3000/

Note that the development build is not optimized.
To create a production build, use npm run build.
```

となれば、OKです。ブラウザーが起動しreact-appが表示されます。
<img width="330" alt="react-app" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18766/69258f55-2aa4-5ef7-bbb6-79a0100084de.png">

## 設定ファイルの準備
```
$ cd my-app/src
$ touch appConfig.tsx
$ vi appConfig.tsx
```

以下の内容を記述します。

```appConfig.tsx
const appConfig = {
    aws: {
        cognito: {
            region: 'ap-northeast-1',
            IdentityPoolId: 'ap-northeast-1:********-****-****-****-************',
            UserPoolId: 'ap-northeast-1_*******',
            ClientId: '***************************'
            GoogleClientID: '*****-**********.apps.googleusercontent.com'
        }
    }
}

export default appConfig
```

## Amplifyで認証機構を準備

```bash
$ yarn add aws-amplify aws-amplify-react
```

```App.tsx
import React, { Component } from 'react';

import logo from './logo.svg';
import Amplify from 'aws-amplify';
import { Authenticator } from 'aws-amplify-react';

import appConfig from './appConfig'

Amplify.configure({
    Auth: {
        identityPoolId: appConfig.aws.cognito.IdentityPoolId,
        region: appConfig.aws.cognito.region,
        userPoolId: appConfig.aws.cognito.UserPoolId,
        userPoolWebClientId: appConfig.aws.cognito.ClientId
    }
});

const federatedConfig = {
    google_client_id: appConfig.aws.cognito.GoogleClientID
};

const App = () => {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.tsx</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}

class AppWithAuth extends Component {
  render(){
    return (
      <div>
          <Authenticator
              federated={federatedConfig}
          >
              <App />
          </Authenticator>
      </div>
    );
  }
}

export default AppWithAuth;
```

再度、起動します。

```bash
$ npm start
```

以下の様なページが保存されます。cognitoでgmailアドレスでアカウントを作って、

<img width="330" alt="amplify coginito & google login" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18766/e25374ae-215c-5ce0-d2e9-5cd2e27910bd.png">

# 感想
大体動作が把握できたので、次はHosted UI使いたいので `amplify init` 使ってコンフィグつくって実装しようと思いました。

Googleのみで利用できるようにして、lambda triggerのpre-signupやauthentcation機能を使ってSignupできるユーザーを事前にUserPool側に登録したユーザーの使えるようにして、細かい制御をする予定です。

自由を手に入れた感じです。