VisasQ Dev Blog

ビザスク開発ブログ

Auth0 Actions の Pre User Registration トリガーで勘違いしていたこと

こんにちは、ビザスク開発グループ クライアント開発チームの松下です。

ビザスクでは認証基盤として Auth0 を導入・検証しています。 調査する中で個人的にハマったポイントについて紹介します。

Auth0 Actions とは

Auth0 には Auth0 Actions という機能があります。 Auth0 Actions を利用すると、以下のようなイベントをトリガーにカスタムロジックを実行することができます。

  • ユーザ登録直前
  • ユーザ登録直後
  • ログイン直後
  • パスワード変更直後

例えばユーザ登録直前(Pre User Registration)に、Auth0 とは別のシステムのユーザ ID を取得し Auth0 のユーザプロファイルに保存したい場合は、以下の手順で Action を登録します。

1. Action を作成する

Actions > Library > Build Custom

今回はトリガーを「Pre User Registration」、Runtime を「Node 16」で作成します。

ダッシュボード上でカスタムロジックを記述することができるので、以下のようなコードを書いていきます。

const axios = require("axios");

/**
 * @param {Event} event - Details about registration event.
 * @param {PreUserRegistrationAPI} api
 */
exports.onExecutePreUserRegistration = async (event, api) => {
  // 別システムのユーザ情報を取得
  const remoteUser = await axios.get("https://my-api.example.com/users", {
    params: { email: event.user.email },
  });
  // 別システムのユーザIDをAuth0側のユーザプロファイルに保存
  api.user.setAppMetadata("my-api-user-id", remoteUser.id);
};

onExecutePreUserRegistration の名の通り、ユーザ登録直前に実行したい処理を自由に書くことができます。

ちなみに依存ライブラリ(axios)の追加もダッシュボード上でおこなえます。

完了したら右上の「Deploy」ボタンを押します。

2. Action を Flow に追加する

Action を登録したら、フローの中に組み込む作業を行います。

Actions > Flows > Pre User Registration

右側の Add ActionCustom を選択すると先程作成した Action が表示されているので、真ん中のエリアにドラッグ&ドロップします。

最後に右上の Apply ボタンを押して完了です。

これでユーザが新規登録する直前に、カスタムロジックが実行されるようになります。

Auth0 Management API でユーザを作成する場合の Pre User Registration の挙動

システムによってはユーザ作成ができるのはユーザ自身だけでなく、システム管理者による操作やバッチプログラムから作成することもあります。

そのような場合、通常のアプリケーションとは別に Machine to Machine(以下M2M)アプリケーションを作成し、Auth0 Management API を利用するのがよくあるパターンです。

M2M アプリケーションを作成する

Applications > Applications > Create application

M2Mアプリケーションを作成します。

Authorized API の指定には「Auth0 Management API」を選択し、必要な Permissions を選択します。(サンプルのため全部選択しています)

これで M2M アプリケーションが作成できました。

Applications > Applications > Sample M2M Application

  • Domain
  • Client ID
  • Client Secret

を控えておきます。

Auth0 Management APIPython から利用する

Auth0 SDK for Python を利用します。

pip install auth0-python

以下のようなコードでユーザを作成できます。domain, client_id, client_secret は先程控えておいた値を入れます。

from auth0.v3.authentication import GetToken
from auth0.v3.management import Auth0

domain = "****"
client_id = "****"
client_secret = "****"

get_token = GetToken(domain)
token = get_token.client_credentials(
    client_id,
    client_secret,
    f"https://{domain}/api/v2/",
)
mgmt_api_token = token["access_token"]
auth0 = Auth0(domain, mgmt_api_token)

# Auth0ユーザ作成
auth0.users.create(
    {
        "email": "test@example.com",
        "email_verified": True,
        "app_metadata": {
            "my-api-user-id": 123,
        },
        "connection": "email",
    }
)

登録自体はこれで問題ないのですが、実はこの Python プログラムからユーザを作成するときにも Pre User Registration トリガーが反応します。

Auth0 Actions に実装するカスタムロジックによっては、「ユーザ自身がサイトから登録したときにしか実行したくない」というケースもあるかと思います。言い換えると、「M2Mアプリケーションから作成されたユーザ登録時のカスタムロジックを無視したい」というケースです。

どのアプリケーションからのユーザ登録かトリガー内で判定する

調べたところ、カスタムロジックに以下のような分岐を加えることで実現できるようです。

const axios = require("axios");

/**
 * @param {Event} event - Details about registration event.
 * @param {PreUserRegistrationAPI} api
 */
exports.onExecutePreUserRegistration = async (event, api) => {
  // 【追加】M2Mアプリケーションからのユーザ登録の場合は以降の処理をおこなわない
  if (event.client.client_id === "****") {
    return;
  }
  // 別システムのユーザ情報を取得
  const remoteUser = await axios.get("https://my-api.example.com/users", {
    params: { email: event.user.email },
  });
  // 別システムのユーザIDをAuth0側のユーザプロファイルに保存
  api.user.setAppMetadata("my-api-user-id", remoteUser.id);
};

**** には先程作成した M2M アプリケーションの client_id が入ります。

公式ドキュメント によると、引数の event からは client 以外にもリクエストの詳細が取得できるようです。特定のIPのみアクセス許可する、といった制御もできそうですね。

終わりに

以上、onExecutePreUserRegistration の意外な挙動の紹介でした。

てっきり Auth0 Actions はユーザ自身が登録するイベントにのみ関係するものだと思いこんでいたのですが、よくよく考えるとユーザ登録の方法なんていくらでも作れますもんね。今回のようなケースがあるので、Auth0 に作成する Application は使い回しをせず、しっかりと用途別に作成するのが良いと感じました。

Auth0 はかなりドキュメントがしっかりしているので、検証作業は結構楽しくやらせてもらっています。引き続き本導入に向けて頑張っていこうと思います 💪