Auth0のユニークな機能 - Automatic Migration編

# はじめに
この記事は[初めてのAuth0ハンズオン](https://qiita.com/hisashiyamaguchi/items/2d0bcae052077f6ae4a4)の続編で、Auth0のユニークな機能の一つである[Automatic Migration](https://auth0.com/docs/users/guides/configure-automatic-migration)の検証手順です。[Automatic Migration](https://auth0.com/docs/users/guides/configure-automatic-migration)は、お客様が既にご利用中の認証DatabaseをAuth0に接続して、認証が発生したタイミングでUser Credentialをシームレスにお客様の認証DatabaseからAuth0のDatabaseに移行する機能です。

# 事前準備
事前に下記をご準備お願いします。

- MacまたはWindows PC
- Chrome
- Node.js, Node Package Manager
- Auth0の無料トライアルアカウント
- Database環境 
**<font color="DarkOrange">MySQL, MongodB, PostreSQL, Oracle等、主要なデータベースであればサポートしています。この記事では[MongoDB Atlas](https://www.mongodb.com/cloud/atlas)で検証しており、詳細な環境構築手順は割愛しています。</font>**

# 検証
## Databaseの設定
左ペインの"Connections"->"Database"をクリック、右上の"CREATE DB CONNECTION"を押します。

<img src="https://i.imgur.com/RHVVu3c.png" width=70%>

"NAME"に任意の名前を入力して下の"CREATE"を押します。

<img src="https://i.imgur.com/DJvktNb.png" width=70%>

"Custom Database"タブをクリックして"User my own database"フリップスイッチをオンにします。
**<font color="DarkOrange">このスイッチをオンにすることで、お客様の認証の認証データベースをAuth0に接続することができます。</font>**

<img src="https://i.imgur.com/3g4gbev.png" width=70%>

"Settings"タブをクリックして"Import Users to Auth0"フリップスイッチをオンにします。
**<font color="DarkOrange">このスイッチをオンにすることで、認証が発生したタイミングでUser Credentialをシームレスにお客様の認証データベースからAuth0のデータベースに移行します。</font>**

<img src="https://i.imgur.com/3HxpwTu.png" width=70%>

"Custom Database"タブをクリックして"Database Action Scripts"->"Login"のに下記のコードを作成して"SAVE"を押します。
**<font color="DarkOrange">"Heads up!"に記載されているGlobal IP AddressからDatabaseにアクセスできるようにDatabase側のセキュリティポリシーを変更お願いします。</font>**


<img src="https://i.imgur.com/0BCQ86K.png" width=70%>

```jsx
function login(email, password, callback) {
  const {MongoClient} = require("mongodb@3.1.4");
  const dbUser = configuration.DBUSER;
  const dbPwd = configuration.DBPWD;
  const dbHost = configuration.DBHOST;
  const dbName = configuration.DBNAME;
  const usersCollection = configuration.USERSCOLLECTION;
  
  const uri = `mongodb+srv://${dbUser}:${dbPwd}@${dbHost}/test?retryWrites=true`;
  const client = new MongoClient(uri, { useNewUrlParser: true });

  client.connect(err => {
    if (err) return callback(err);

    const collection = client.db(dbName).collection(usersCollection);

    collection.findOne({email: email, password}, (err, user) => {
      if (err) return callback(err);
      if (!user) return callback(null);
      const profile  = {
        ...user,
        user_id: user.email,
        app_metadata: {
      	  migrated: true
        }
      };
      callback(null, profile);
      client.close();
    });
  });
}
```

"Settings"でDatabaseの環境変数を設定します。
**<font color="DarkOrange">接続するDatabaseの環境に沿って変数を設定して下さい。</font>**


- DBUSER
- DBPWD
- DBHOST
- DBNAME
- USERCOLLECTION

<img src="https://i.imgur.com/8ezicUI.png" width=70%>

"TRY"ボタンを押してDatabase-Tableに存在するUser Credentialを入力して"TRY"を押します。"The profile is:xxx"が返ってきたら成功です。

<img src="https://i.imgur.com/wz4xI2p.png" width=70%>

## Applicationの設定
[初めてのAuth0ハンズオン](https://qiita.com/hisashiyamaguchi/items/2d0bcae052077f6ae4a4)ので作成したApplicationをクリック、"Connections"タブをクリックして作成したDatabase以外のフリップスイッチをオフにします。

<img src="https://i.imgur.com/HC388os.png" width=70%>


## 動作確認
Applicationを起動、Chromeで`http://localhost:3000`にアクセスしてDatabase上に存在するUser Credentialでログインします。

```console
$ pwd
~/auth0-react-samples/01-Login
$ npm start
```

<img src="https://i.imgur.com/tgIYIDP.png" width=70%>
<img src="https://i.imgur.com/x28NDJ1.png" width=70%>

"Users&Roles"->"Users"をクリック、移行されたユーザをクリックしてapp_metadataに"Migrated : true"フラグが立っていることを確認します。

<img src="https://i.imgur.com/sTtiGjm.png" width=70%>

**<font color="DarkOrange">[補足]どのカラムがIDかは下記のコードブロックで指定しています。"    collection.findOne({email: email, password}, (err, user) => {"のはじめの"email"でemailがIDであることを指定しています。Databaseのスキーマに応じて変更お願いします。</font>**

```jsx
    collection.findOne({email: email, password}, (err, user) => {
      if (err) return callback(err);
      if (!user) return callback(null);
      const profile  = {
        ...user,
        user_id: user.email,
        app_metadata: {
          migrated: true
        }
      };
      callback(null, profile);
      client.close();
    });
```

# おわりに
User Credentialの移行で最も頭が痛いのは、エンドユーザ様にパスワードリセットを強要しなければならないことかと思います。パスワードリセットの要求を受けたエンドユーザ様は、何故？何かセキュリティ関連の事故でもあったの？と不安を駆り立てられ、それが原因で会員を退会してしまうかもしれません。Auth0はハッシュで暗号化されたパスワードをAuth0のハッシュアルゴリズム(bcrypt)再ハッシュしてAuth0のDatabaseに移行するため、エンドユーザ様にてパスワードをリセット頂くことなくシームレスに移行できることが特徴です。