Auth0 アカウントリンクを試す

2020.03.03

Auth0は、デフォルトですべてのIDを別個のものとして扱います。

例えば、最初にAuth0データベースに対してログインし、次にGoogleでログインした場合、これら2つの試行はAuth0からは2人の別個のユーザーとして表示されます。

Auth0ではユーザーアカウントリンクというのがサポートされており、これによりユーザーは自分のアカウントのいずれかから認証され、アプリによって認識され、同じユーザープロファイルに関連付けられます。

利点は以下です。

  • 個別のプロファイルを作成せずに、任意のIDプロバイダーでログインできる
  • 新しいソーシャルログインまたはパスワードなしのログインを使用できますが、既存のプロファイルは引き続き使用できます
  • パスワードなしのログインを使用して登録したユーザーが、より完全なプロファイルを持つアカウントにリンクできるようにします
  • アプリがさまざまな接続に保存されているユーザープロファイルデータを取得できるようにします

引用元: Auth0ドキュメント ユーザーアカウントのリンク

では実際にアカウントリンクを行ったらどういう風に見えるのか試してみようと思います。

やってみる

Node.jsレギュラーWebアプリを使います。

Auth0にサンプルが用意されているため、使わせてもらいます。

  • nodejsのバージョン: v12.13.0
  • OS: macOS Mojave 10.14.6

Auth0でアプリケーションの作成と設定

ダッシュボードで新規アプリケーションを作成します。

作成したアプリケーションの設定画面に行き、

  • Allowed Callback URLshttp://localhost:3000/callback
  • Token Endpoint Authentication Method に None

を設定しますします。

read:usersおよびupdate:usersスコープでAPIv2トークンを生成

Auth0 Management API`のアクセストークンを取得します。

read:users, update:users が必要です

$ curl --request POST \
>   --url https://{your_auth0_domain}/oauth/token \
>   --header 'content-type: application/json' \
>   --data '{"client_id":"{your_client_id}","client_secret":"{your_client_secret}","audience":"https://{your_auth0_domain}/api/v2/","grant_type":"client_credentials"}'
{"access_token":"アクセストークン","scope":"read:users update:users","expires_in":86400,"token_type":"Bearer"}

アクセストークンは次の手順で使用するのでコピーしておきます。

サンプルアプリのインストール

ターミナルを起動し、任意の場所に移動し、サンプルアプリをcloneします

$ cd {サンプルアプリのディレクトリ}
$ git clone https://github.com/auth0-samples/auth0-link-accounts-sample.git
$ cd auth0-link-accounts-sample/RegularWebApp/

sample.envファイルを自身の環境に合わせて修正します。

$ mv sample.env .env
$ vi .env
AUTH0_CLIENT_ID=your-auth0-client-id
AUTH0_CLIENT_SECRET=your-auth0-client-secret
AUTH0_DOMAIN=your-auth0-domain
AUTH0_CALLBACK_URL=http://localhost:3000/callback
AUTH0_APIV2_TOKEN=your-auth0-api-v2-token

以下のコマンドでインストールし、アプリを立ち上げます。

$ npm install
$ npm run start

ブラウザでhtt@://localhost:3000にアクセスします

サンプルアプリの確認

アカウントリンク機能をサンプルアプリを使って試します。

LOGINボタンをクリックし、Sign Upタブをクリックします。

メールアドレスとパスワードを入力し、ユーザー登録を行います。 アプリの認証ダイアログが出ますが、許可ボタンをクリックします。

ユーザー登録完了後、自動的にログインされます。

providerがauth0, connectionがUsername-Password-Authenticationのユーザーが作成されました。

ユーザープロファイル

{
  "created_at": "2020-03-03T10:11:24.532Z",
  "email": "mori.ryosuke@classmethod.jp",
  "email_verified": false,
  "identities": [
    {
      "user_id": "5e5e2d4c9a67390d46dec91e",
      "provider": "auth0",
      "connection": "Username-Password-Authentication",
      "isSocial": false
    }
  ],
  "name": "mori.ryosuke@classmethod.jp",
  "nickname": "mori.ryosuke",
  ~~~~~~~~~~~~~~~~~
  ~~~~~~~~~~~~~~~~~
  ~~~~~~~~~~~~~~~~~
  ~~~~~~~~~~~~~~~~~
  ~~~~~~~~~~~~~~~~~
}

このユーザーにアカウントをリンクさせます。

※ サンプルアプリではメールアドレスの確認を終えていないとアカウントリンクされないので、最初のユーザーを作った後、メールボックスを確認してメール確認のリンクをクリックしておきましょう。

一度ログアウトします。

LOGINボタンを押してダイアログを起動し、Log in with Googleを押してサンプルアプリにログインします。

※ アカウントリンクをするには、先ほど作ったユーザーと同じメールアドレスのgoogleアカウントが必要です。

進めていくとサンプルアプリにリダイレクトされますが、そこで Link Accounts のダイアログが立ち上がるはずです。

Linkボタンを押してリンクしましょう。

Linked Accountsのボックスに先ほどまでなかった情報が表示されてます。リンクは成功していますね。

ユーザープロファイル

{
  "created_at": "2020-03-03T11:14:38.766Z",
  "email": "mori.ryosuke@classmethod.jp",
  "email_verified": true,
  "family_name": "森",
  "given_name": "亮介",
  "identities": [
    {
      "provider": "google-oauth2",
      "access_token": "ya29.a0Adw1xeX8rrDQrZT6fREYhtD2gscAOOZxRyGlktO-VowFIRfsV8eOkOTiNIChSRP-B47ZNfUi7r30ANiDo3wmuMOhs2Wq24hyqN_WCgFrXG0iQ8Z_ine6lDPWOdBcF9VOtmiOGYoIWVMVSXL1N1FI_NqNtLJQOqYBZarN",
      "expires_in": 3599,
      "user_id": "118272837942600975202",
      "connection": "google-oauth2",
      "isSocial": true
    },
    {
      "profileData": {
        "email": "mori.ryosuke@classmethod.jp",
        "email_verified": true
      },
      "user_id": "5e5e3a3acd78360d6f8522d1",
      "provider": "auth0",
      "connection": "Username-Password-Authentication",
      "isSocial": false
    }
  ],
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  以下省略
}

リンクされると、identitiesにリンク先、リンク元の情報が追加されます。

一旦ログアウトし、パスワードユーザーでログインしてみても、

プロフィール情報は同じです。

もうちょっと詳しく確認してみる

アカウントがリンクされることはわかりましたが、パスワードユーザーでログインしてもgoogleアカウントのプロファイルがメインで表示されています。

"user_id": "google-oauth2|118272837942600975202"

これは、サンプルアプリの中で、

googleアカウントのユーザーをプライマリーアカウント、パスワードユーザーをセカンダリーアカウントとしてリンクしたからです。

APIのドキュメントも確認してみます。

/api/v2/users/{id}/identities

Link two user accounts together forming a primary and secondary relationship. On successful linking, the endpoint returns the new array of the primary account identities.

リンクが成功すると、エンドポイントはプライマリアカウントIDの新しい配列を返します と書かれています。

APIの実行に必要なパラメーターは

  • id : プライマリアカウントとして使用するuser_id
  • body : セカンダリアカウントとして使用するユーザーのプロファイル情報
    • provider: セカンダリアカウントのプロバイダー名
    • connection_id: セカンダリアカウントのconnection_id
    • user_id: セカンダリアカウントのuser_id
    • link_with: リンクされるセカンダリアカウントのJWT。このパラメーターを送信する場合、provider、user_id、およびconnection_idは送信しない

です。

サンプルアプリでもこのAPIを実行しています。

コードはこちら

Auth0のダッシュボードでユーザー一覧を見てみると、

このように Connectiongoogle-oauth2 のユーザー一つだけになっています。

今回の手順でリンクしたプライマリーアカウントの情報が表示されていることがわかります。

最後に

Auth0のアカウントリンクをサンプルアプリを使って確認してみました。

サンプルアプリで行われたことは以下です。

  • ユーザーを認証する
  • メールアドレスを使用してユーザーを検索および識別します
  • ユーザーにアカウントのリンクを促す
  • メタデータの検証とマージ
  • アカウントをリンクする

Auth0のデフォルトだと同じメールアドレスでも接続方法が違うと別ユーザーとして扱われますが、リンクしてしまえば一つのユーザーとして扱え、 他の接続方法のアカウントとプロファイル情報を共有できるため結構便利な機能だと思います。

アカウントをリンクする前にuser_metadataapp_metadataをマージして共有することもできます。

※今回使用したサンプルアプリでも自動で行われるようになっています。

コードはこちら

このようなリンクを自身で実装するとなるとかなりの手間が想定されますが、Auth0ではAPIとして提供してくれているので容易に導入することができます。

記事の最初の方に記載したアカウントリンクの利点を生かしたいのであればぜひ試してみてください。

参考