Auth0のユニークな機能 - Linking User Accounts編その2

# はじめに
この記事は[初めてのAuth0ハンズオン](https://qiita.com/hisashiyamaguchi/items/2d0bcae052077f6ae4a4)と[Auth0のユニークな機能 - Linking User Accounts編その1](https://qiita.com/hisashiyamaguchi/items/5a53746839f38be607a1)の続編で、Auth0のユニークな機能の一つである[Linking User Accounts](https://auth0.com/docs/link-accounts)の応用編です。[Auth0のManagement API](https://auth0.com/docs/api/management/v2)で公開しているEnd Pointにhttpリクエストを送信してアカウントをリンク・アンリンクしてどのような挙動をするか確認しています。

# 検証
## リンク
同じEmail Addressを持っているGoogleとFacebookのアカウントでリンクしてみます。[Management API](https://auth0.com/docs/api/management/v2#!/Users/post_identities)にPostリクエストを送信してGoogleとFacebookのアカウントをリンクします。

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

Auth0 Dashboardの左ペイン”APIs”をクリック、”Auth0 Management API”を選択して"API Explorer"タブをクリックして”Token”をクリップボードにコピーします。
**<font color="DarkOrange">このTokenはManagement APIへのフル権限を持ったTokenです。このTokenをManagement APIのドキュメントにセットしてダイナミックなcurlコマンドを作成します。</font>**

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

[Management API](https://auth0.com/docs/api/management/v2)左上の"SET API TOKEN"をクリックしてクリップボードにコピーしたTokenをペーストして”SET TOKEN”を押します。

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

[/api/v2/users/{id}/identities End Point](https://auth0.com/docs/api/management/v2#!/Users/post_identities)にPostリクエストを送信するcurlコマンドを生成します。

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

"id"にはPrimary Providerアカウントのuser_idを指定します。例 : google-oauth2|109026600466545709878
"body"にはSecondary ProviderアカウントのProviderとuser_idを指定します。以下、例です。

```json
{
  "provider": "facebook",
  "user_id": "2139237436182114"
}
```

"get curl command"をクリックして生成されたコマンドをターミナルにコピーペーストして実行します。

```console
$ curl -H "Authorization: Bearer eyJhxxxx" -X POST  -H "Content-Type: application/json" -d '{"provider":"facebook","user_id":"2139237436182114"}' https://pannacotta.auth0.com/api/v2/users/google-oauth2%7C109026600466545709878/identities
```

Dashboard左ペインの"Users & Roles"->"Users"をクリックしてアカウントがリンクされていることを確認します。アカウントをクリックして”Row JSON"タブをクリック、リンクされたJSONを確認します。

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

```json
{
    "created_at": "2020-01-25T03:47:12.864Z",
    "email": "cookiewanwan@gmail.com",
    "email_verified": true,
    "family_name": "Yamaguchi",
    "given_name": "Hisashi",
    "identities": [
        {
            "provider": "google-oauth2",
            "user_id": "109026600466545709878",
            "connection": "google-oauth2",
            "isSocial": true
        },
        {
            "profileData": {
                "name": "Hisashi  Yamaguchi",
                "email": "cookiewanwan@gmail.com",
                "given_name": "Hisashi",
                "family_name": "Yamaguchi",
                "picture": "https://platform-lookaside.fbsbx.com/platform/profilepic/?asid=2139237436182114&height=50&width=50&ext=1582516018&hash=AeT52yBpX6StcIp0",
                "picture_large": "https://platform-lookaside.fbsbx.com/platform/profilepic/?asid=2139237436182114&width=999999&ext=1582516018&hash=AeSGejrtfDA7-Ovc",
                "name_format": "{first} {last}",
                "short_name": "Hisashi  Yamaguchi",
                "installed": true,
                "install_type": "UNKNOWN",
                "security_settings": {
                    "secure_browsing": {
                        "enabled": true
                    }
                },
                "video_upload_limits": {
                    "length": 14460,
                    "size": 28633115306
                },
                "viewer_can_send_gift": false,
                "email_verified": true
            },
            "user_id": "2139237436182114",
            "provider": "facebook",
            "connection": "facebook",
            "isSocial": true
        }
    ],
    "locale": "ja",
    "name": "Hisashi Yamaguchi",
    "nickname": "cookiewanwan",
    "picture": "https://lh3.googleusercontent.com/a-/AAuE7mDS46tGHm2lQW8iHqYTC_Cgv0DtKCqGT88IUBiAoA",
    "updated_at": "2020-01-25T04:01:05.164Z",
    "user_id": "google-oauth2|109026600466545709878",
    "last_ip": "126.233.110.117",
    "last_login": "2020-01-25T03:49:43.857Z",
    "logins_count": 4,
    "blocked_for": [],
    "guardian_authenticators": []
}
```

## アンリンク
リンクしたアカウントをアンリンクします。[/api/v2/users/{id}/identities/{provider}/{user_id} End Point](https://auth0.com/docs/api/management/v2#!/Users/delete_user_identity_by_user_id)Deleteリクエストを送信するcurlコマンドを生成します。
"id"にはプライマリアカウントのuser_id(例/google-oauth2|109026600466545709878)、"provider"はセカンダリアカウントのProviderを選択します。"user_id"はセカンダリアカウントのid(例/2139237436182114)を選択します。

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

"get curl command"をクリックして生成されたコマンドをターミナルにコピーペーストして実行します。

```console
$ curl -H "Authorization: Bearer eyJhxxxx" -X DELETE  https://pannacotta.auth0.com/api/v2/users/google-oauth2%7C109026600466545709878/identities/facebook/2139237436182114
```
Dashboard左ペインの"Users & Roles"->"Users"をクリックしてアカウントがアンリンクされていることを確認します。アカウントをクリックして”Row JSON"タブをクリック、各々のアカウントのJSONを確認します。

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

```json
{
    "created_at": "2020-01-25T04:53:39.295Z",
    "email": "cookiewanwan@gmail.com",
    "email_verified": true,
    "family_name": "Yamaguchi",
    "given_name": "Hisashi",
    "identities": [
        {
            "provider": "google-oauth2",
            "user_id": "109026600466545709878",
            "connection": "google-oauth2",
            "isSocial": true
        }
    ],
    "locale": "ja",
    "name": "Hisashi Yamaguchi",
    "nickname": "cookiewanwan",
    "picture": "https://lh3.googleusercontent.com/a-/AAuE7mDS46tGHm2lQW8iHqYTC_Cgv0DtKCqGT88IUBiAoA",
    "updated_at": "2020-01-25T04:57:03.493Z",
    "user_id": "google-oauth2|109026600466545709878",
    "last_ip": "126.233.110.117",
    "last_login": "2020-01-25T04:53:39.293Z",
    "logins_count": 1,
    "blocked_for": [],
    "guardian_authenticators": []
}
```

```json
{
    "created_at": "2020-01-25T04:57:03.504Z",
    "email": "cookiewanwan@gmail.com",
    "email_verified": true,
    "family_name": "Yamaguchi",
    "given_name": "Hisashi",
    "identities": [
        {
            "user_id": "2139237436182114",
            "provider": "facebook",
            "connection": "facebook",
            "isSocial": true
        }
    ],
    "install_type": "UNKNOWN",
    "installed": true,
    "name": "Hisashi  Yamaguchi",
    "name_format": "{first} {last}",
    "nickname": "cookiewanwan",
    "picture": "https://platform-lookaside.fbsbx.com/platform/profilepic/?asid=2139237436182114&height=50&width=50&ext=1582520028&hash=AeTSH7GmePNsGvwn",
    "picture_large": "https://platform-lookaside.fbsbx.com/platform/profilepic/?asid=2139237436182114&width=999999&ext=1582520028&hash=AeT883zuqfADtrs3",
    "security_settings": {
        "secure_browsing": {
            "enabled": true
        }
    },
    "short_name": "Hisashi  Yamaguchi",
    "updated_at": "2020-01-25T04:57:03.504Z",
    "user_id": "facebook|2139237436182114",
    "video_upload_limits": {
        "length": 14460,
        "size": 28633115306
    },
    "viewer_can_send_gift": false,
    "blocked_for": [],
    "guardian_authenticators": [
        {
            "id": "recovery-code|dev_9PC19jCFChrstsGC",
            "type": "recovery-code",
            "confirmed": false,
            "created_at": "2020-01-24T01:25:01.000Z"
        },
        {
            "id": "totp|dev_Wa4yTOU6gGWs1LKB",
            "type": "totp",
            "confirmed": false,
            "created_at": "2020-01-24T01:25:01.000Z"
        }
    ]
}
```

# おわりに
Auth0はJSONオブジェクトでユーザ属性を管理しており、柔軟にアカウントをリンク・アンリンクすることができます。リンクされたSecondary Providerのアカウントが持っていたJSONオブジェクトは物理的にDatabase上から削除され、アンリンクされたタイミングで再度JSONオブジェクを作成しています。物理削除なのでストレージスペースを節約できて検索性能の劣化も回避できますね。