メインコンテンツへスキップ
ユーザーの保存に Auth0 ホスト型のデータベース構成を使用している場合は、同じテナントまたは別のテナントに対してユーザー認証を行うことで、その接続をテストできます。

Auth0 へのユーザーのインポートを有効にしてテストする

ユーザーのインポートを有効にすると、ユーザーは外部ユーザーストアから Auth0 のユーザーストアへ段階的に移行されます。この過程では、ユーザーが初回のログインに成功した際に、外部ストアに対して認証されます。以降のログイン試行はすべて、Auth0 のユーザーストアに対して行われます。詳細については、Import and Export Users の自動移行に関する説明を参照してください。

テスト用のテナントとアプリケーションを作成する

  1. Auth0 Dashboard を使用して、新しいテナントを作成します。
  2. Applications > Applications に移動し、Machine-to-Machine アプリケーションを作成します。
    カスタムデータベーススクリプトを作成するときに、クライアントIDクライアントシークレット を控えておく必要があります。Management API でスコープを有効にするには、クライアントID が必要です。
  3. このアプリケーションで、PasswordClient Credential の両方のグラントを有効にします (このテストでは両方のグラントを有効にする必要があります) 。
    Auth0 Dashboard > Applications > Advanced Settings
  4. アプリケーションを認可するには、Applications > APIs に移動します。
  5. Management API を選択します。
  6. Machine-to-Machine Applications タブで、トグルを使用してテスト用アプリケーションを認可します。
  7. ドロップダウンメニューを選択し、次の Auth0 Management API スコープを有効にします。
    • read:users
    • update:users
    • delete:users
    • create:users
    • read:users_app_metadata
    • update:users_app_metadata
    • create:users_app_metadata
      Auth0 Dashboard > APIs > Management API >  M2M Tab > App Permissions

テスト用データベース接続を作成する

Dashboard でテナントとアプリケーションを作成したら、ソースのデータベース接続とターゲットのデータベース接続を作成します。
  1. ソースとして使用する新しいデータベース接続を作成するには、Authentication > Database に移動します。
  2. テスト用のソース接続に名前を付け、Requires Username を有効にして、Create を選択します。
    テストで使用するユーザーは、User Management > Users に移動して作成できます。Create Users を選択して必要な項目を入力したら、Connection フィールドでソースデータベースを選択します。
  3. 手順 2 と同じ設定で、ターゲットとして使用する 2 つ目のデータベースを作成します。
    テストで簡単なパスワードを使用できるように、ターゲットとソースの両方のデータベースで Password PolicyNon-empty password required に設定できます。
  4. ターゲットデータベースで Custom Database ビューに切り替え、Use my own database をオンにします。
    カスタムデータベースで組織を使ってテストする場合は、Context object in database scripts を有効にします。
  5. Settings ビューに切り替え、Import Users to Auth0 を有効にします。
  6. Custom Database ビューに切り替えて、Database settings セクションを見つけます。手順 1 で作成したソースデータベースから、次の情報を追加します。
KeyValue
client_id作成したアプリケーションのクライアントID。
client_secret作成したアプリケーションのクライアントシークレット。
auth0_domainAuth0 ドメイン内のテナント名 (例: yourTenant.us.auth0.com) 。
source_databaseソース接続の名前。
  1. ターゲットデータベースで、LoginGet User のデータベースアクションスクリプトを更新します。データベースアクションスクリプトを使用する際のベストプラクティスについて詳しくは、Custom Database Connection and Action Scripts Best Practices を参照してください。
  2. 各スクリプトで Save and Try を選択します。Actions Real-time Logs で console.log の出力を確認してください。詳しくは、Actions Real-time Logs を参照してください。
  3. Try Connection を選択して、接続をその場でテストします。

Import Users を有効にしないでテストする

  1. テスト用のテナントとアプリケーションを作成する の手順を繰り返します。
  2. テスト用のデータベース接続を 1 つ作成します。
  3. ソースデータベース設定の Import Users to Auth0 が無効になっていることを確認します。ユーザーはログインを試行するたびに、外部ユーザーストアで認証されます。
  4. すべてのデータベース アクションスクリプトを、以下のサンプルで更新します。

Get User スクリプト

Get User スクリプトは、ユーザーの現在の状態を判定する実行可能な関数を実装するものです。 Import Users to Auth0 が有効な場合、Get User スクリプトは、ユーザーがサインアップを試みたときに実行され、外部ユーザーストアにそのユーザーがすでに存在するかどうかを確認します。 Get User スクリプトは、ユーザーが次のいずれかを試みた場合にも実行されます。
  • ユーザーのメールアドレスを変更する (Change Email スクリプト)
  • ログインする (Login スクリプト)
  • ユーザーのパスワードを変更する (Change Password スクリプト)
Import Users to Auth0 が無効な場合も、Get User スクリプトは、ユーザーがサインアップを試みたときに実行され、外部ユーザーストアにそのユーザーがすでに存在するかどうかを確認します。ユーザーが外部ユーザーストアにすでに存在する場合、Create スクリプトは実行されません。 Get User スクリプトは、ユーザーが次のいずれかを試みた場合にも実行されます。
  • ユーザーを作成する (Create スクリプト)
  • ユーザーのメールアドレスを変更する (Change Email スクリプト)
  • ユーザーのパスワードを変更する (Change Password スクリプト)

async function getUser(user, context, callback) {
    log(`Script started.`);
    log(`Requesting an Access Token from "${configuration.auth0_domain}".`);
    let accessToken = await getAccessToken();
    accessToken = accessToken.access_token;
    if (!accessToken) return log(`Failed to get an Access Token from "${configuration.auth0_domain}".`, true);
    log(`The Access Token is available. Searching for user "${user}" in "${configuration.source_database}"`);
    user = user.toLowerCase();
    const searchQuery = encodeURI(`identities.connection:"${configuration.source_database}"+AND+(email:${user} OR username:${user})`);
    var options = {
        method: `GET`,
        url: `https://${configuration.auth0_domain}/api/v2/users?q=${searchQuery}`,
        headers: {
            Authorization: `Bearer ${accessToken}`,
        }
    };
    request(options, function (error, response) {
        if (error) return log(`Cannot connect to "${configuration.source_database}" database.`, true);
        let search_results = JSON.parse(response.body);
        let profile = null;
        if (search_results.length > 0) {
            log(`A user "${user}" is FOUND in "${configuration.source_database}" database.`);
            profile = {
                user_id: search_results[0].user_id.toString(),
                nickname: search_results[0].nickname,
                username: search_results[0].username,
                email: search_results[0].email
            };
        } else {
            log(`A user "${user}" is NOT FOUND in "${configuration.source_database}" database.`);
        }
        log(`Script completed!`);
        return callback(null, profile);
    });
    /* -- クライアントクレデンシャルでアクセストークンを取得 -- */
    async function getAccessToken() {
        var options = {
            method: `POST`,
            url: `https://${configuration.auth0_domain}/oauth/token`,
            headers: {
                "Content-Type": `application/x-www-form-urlencoded`,
            },
            form: {
                grant_type: `client_credentials`,
                client_id: configuration.client_id,
                client_secret: configuration.client_secret,
                audience: `https://${configuration.auth0_domain}/api/v2/`
            },
            json: true
        };
        return new Promise(function (resolve) {
            request(options, function (error, response) {
                resolve(error || response.body);
            });
        });
    }
    /* -- ログ記録 -- */
    function log(message, error = false) {
        const script_name = `GET USER`;
        const error_label = error ? `(ERROR)` : ``;
        const return_message = `${script_name}: ${error_label} ${message}`;
        console.log(return_message);
        if (error) return callback(new Error(return_message));
    }
}

ログインスクリプト

Login スクリプトは、ユーザーのログイン時に認証を行う実行可能な関数を実装します。対象データベース (Auth0) にユーザーが存在する場合は、そのレコードを使用して認証します。存在しない場合は、ソースデータベース (外部) 内のユーザーのレコードを使用して認証します。

function login(usernameOrEmail, password, context, callback) {
  log(`Script started.`);
  const jwt = require('jsonwebtoken');
  const options = {
    method: `POST`,
    url: `https://${configuration.auth0_domain}/oauth/token`,
    headers: { "Content-Type": `application/x-www-form-urlencoded` },
    json: true,
    form: {
      grant_type: `http://auth0.com/oauth/grant-type/password-realm`,
      client_id: configuration.client_id,
      client_secret: configuration.client_secret,
      username: usernameOrEmail,
      password: password,
      realm: `${configuration.source_database}`
    }
  };
  request(options, function (error, response, body) {
    log(`Attempting to authenticate a user "${usernameOrEmail}" against "${configuration.source_database}" database in "${configuration.auth0_domain}" tenant.`);
    if (error) return log(`Cannot connect to "${configuration.auth0_domain}" database.`, true);
    if (response.statusCode !== 200) {
      console.log(`LOGIN: (ERROR) ${response.body.error_description}`);
      return callback(new WrongUsernameOrPasswordError(usernameOrEmail, `LOGIN: (ERROR) ${response.body.error_description}`));
    }
    log(`Successfuly authenticated user "${usernameOrEmail}" against "${configuration.source_database}" database in "${configuration.auth0_domain}" tenant.`);
    const decoded_id_token = jwt.decode(body.id_token);
    const profile = {
      user_id: decoded_id_token.sub,
      nickname: decoded_id_token.nickname,
      username: decoded_id_token.username,
      email: decoded_id_token.email
    };
    log(`Script completed.`);
    return callback(null, profile);
  });
  /* -- ログ記録 -- */
  function log(message, error = false) {
    const script_name = `LOGIN`;
    const error_label = error ? `(ERROR)` : ``;
    const return_message = `${script_name}: ${error_label} ${message}`;
    console.log(return_message);
    if (error) return callback(new Error(return_message));
  }
}

作成スクリプト

作成スクリプト は、ユーザーが 経由でサインアップしたとき、または や Auth0 を使用して作成されたときに、外部データベースに対応するユーザーレコードを作成する実行可能な関数を実装します。

async function create(user, context, callback) {
  log(`Script started.`);
  log(`Requesting an Access Token from "${configuration.auth0_domain}".`);
  let accessToken = await getAccessToken();
  if (!accessToken.access_token) return log(`Failed to get an Access Token from "${configuration.auth0_domain}".`, true);
  accessToken = accessToken.access_token;
  log(`The Access Token is available. Attempting to create a user "${user.email}" in "${configuration.source_database}"`);
  const options = {
    method: `POST`,
    url: `https://${configuration.auth0_domain}/api/v2/users`,
    headers: {
      Authorization: `Bearer ${accessToken}`,
      "Content-Type": `application/x-www-form-urlencoded`
    },
    form: {
      connection: configuration.source_database,
      email: user.email,
      password: user.password,
      username: user.username
    },
    json: true
  };
  request(options, function (error, response) {
    if (error) return log(`Cannot connect to "${configuration.source_database}" database.`, true);
    switch (response.statusCode) {
      case 201:
        log(`The user "${user.email}" is successfuly created in "${configuration.source_database}" database.`);
        return callback(null);
      case 409:
        return callback(new ValidationError(`user_exists`, `The user already exists in "${configuration.source_database}" database.`));
      default:
        return log(`Failed to create a user "${user.email}" in "${configuration.source_database}" database. Error: "${response.statusCode}, ${response.body.message}"`, true);
    }
  });
  /* -- クライアントクレデンシャルでアクセストークンを取得 -- */
  async function getAccessToken() {
    var options = {
      method: `POST`,
      url: `https://${configuration.auth0_domain}/oauth/token`,
      headers: {
        "Content-Type": `application/x-www-form-urlencoded`,
      },
      form: {
        grant_type: `client_credentials`,
        client_id: configuration.client_id,
        client_secret: configuration.client_secret,
        audience: `https://${configuration.auth0_domain}/api/v2/`
      },
      json: true
    };
    return new Promise(function (resolve) {
      request(options, function (error, response) {
        resolve(error || response.body);
      });
    });
  }
  /* -- ログ記録 -- */
  function log(message, error = false) {
    const script_name = `CREATE`;
    const error_label = error ? `(ERROR)` : ``;
    const return_message = `${script_name}: ${error_label} ${message}`;
    console.log(return_message);
    if (error) return callback(new Error(return_message));
  }
}

削除スクリプト

削除スクリプト では、Auth0 Dashboard または Auth0 Management API でユーザーが削除されたときに、同じ操作で Auth0 と外部データベースの両方からユーザーを削除する実行可能な関数を実装します。

async function deleteUser(user, context, callback) {
  log(`Script started.`);
  log(`Requesting an Access Token from "${configuration.auth0_domain}".`);
  let accessToken = await getAccessToken();
  if (!accessToken.access_token) return log(`Failed to get an Access Token from "${configuration.auth0_domain}".`, true);
  accessToken = accessToken.access_token;
  log(`The Access Token is available. Attempting to delete a user "${user}" from "${configuration.source_database}"`);
  const options = {
    method: `DELETE`,
    url: `https://${configuration.auth0_domain}/api/v2/users/${user}`,
    headers: {
      Authorization: `Bearer ${accessToken}`,
      "Content-Type": `application/x-www-form-urlencoded`
    },
    json: true
  };
  request(options, function (error, response) {
    if (error) return log(`Cannot connect to "${configuration.source_database}" database.`, true);
    switch (response.statusCode) {
      case 204:
        log(`The user "${user}" is successfuly deleted from "${configuration.source_database}" database.`);
        return callback(null);
      default:
        return log(`Failed to delete a user "${user}" from "${configuration.source_database}" database. Error: "${response.statusCode}, ${response.body.message}"`, true);
    }
  });
  /* -- クライアントクレデンシャルでアクセストークンを取得 -- */
  async function getAccessToken() {
    var options = {
      method: `POST`,
      url: `https://${configuration.auth0_domain}/oauth/token`,
      headers: {
        "Content-Type": `application/x-www-form-urlencoded`,
      },
      form: {
        grant_type: `client_credentials`,
        client_id: configuration.client_id,
        client_secret: configuration.client_secret,
        audience: `https://${configuration.auth0_domain}/api/v2/`
      },
      json: true
    };
    return new Promise(function (resolve) {
      request(options, function (error, response) {
        resolve(error || response.body);
      });
    });
  }
  /* -- ログ記録 -- */
  function log(message, error = false) {
    const script_name = `DELETE`;
    const error_label = error ? `(ERROR)` : ``;
    const return_message = `${script_name}: ${error_label} ${message}`;
    console.log(return_message);
    if (error) return callback(new Error(return_message));
  }
}

Verify スクリプト

Verify スクリプト は、Auth0 から送信された確認メール内のリンクをユーザーがクリックしたときに、外部データベース内のユーザーのメールアドレスの確認状態を確認済みにする実行可能な関数を実装します。

async function verify(user, context, callback) {
  log(`Script started.`);
  log(`Requesting an Access Token from "${configuration.auth0_domain}".`);
  let accessToken = await getAccessToken();
  if (!accessToken.access_token) return log(`Failed to get an Access Token from "${configuration.auth0_domain}".`, true);
  accessToken = accessToken.access_token;
  log(`The Access Token is available. Searching for user "${user}" in "${configuration.source_database}"`);
  user = user.toLowerCase();
  const searchQuery = encodeURI(`identities.connection:"${configuration.source_database}"+AND+(email:${user} OR username:${user})`);
  var options = {
    method: `GET`,
    url: `https://${configuration.auth0_domain}/api/v2/users?q=${searchQuery}`,
    headers: {
      Authorization: `Bearer ${accessToken}`,
    }
  };
  request(options, function (error, response) {
    if (error) return log(`Cannot connect to "${configuration.source_database}" database.`, true);
    let search_results = JSON.parse(response.body);
    if (search_results.length > 0) {
      log(`A user "${user}" is found in "${configuration.source_database}" database.`);
      const user_id = search_results[0].user_id.toString();
      log(`Attempting to mark user "${user_id}" as verified in "${configuration.source_database}" database`);
      const options = {
        method: `PATCH`,
        url: `https://${configuration.auth0_domain}/api/v2/users/${user_id}`,
        headers: {
          Authorization: `Bearer ${accessToken}`,
          "Content-Type": `application/x-www-form-urlencoded`
        },
        form: {
          email_verified: true,
        },
        json: true
      };
      request(options, function (error, response) {
        if (error) return log(`Cannot connect to "${configuration.source_database}" database.`, true);
        switch (response.statusCode) {
          case 200:
            log(`The user "${user}" is marked as verified in "${configuration.source_database}" database.`);
            return callback(null, true);
          default:
            return log(`Failed to mark a user "${user}" as verified in "${configuration.source_database}" database. Error: "${response.statusCode}, ${response.body.message}"`, true);
        }
      });
    } else {
      log(`A user "${user}" is not found in "${configuration.source_database}" database. Unable to verify.`, true);
    }
  });
  /* -- クライアントクレデンシャルでアクセストークンを取得 -- */
  async function getAccessToken() {
    var options = {
      method: `POST`,
      url: `https://${configuration.auth0_domain}/oauth/token`,
      headers: {
        "Content-Type": `application/x-www-form-urlencoded`,
      },
      form: {
        grant_type: `client_credentials`,
        client_id: configuration.client_id,
        client_secret: configuration.client_secret,
        audience: `https://${configuration.auth0_domain}/api/v2/`
      },
      json: true
    };
    return new Promise(function (resolve) {
      request(options, function (error, response) {
        resolve(error || response.body);
      });
    });
  }
  /* -- ログ記録 -- */
  function log(message, error = false) {
    const script_name = `VERIFY`;
    const error_label = error ? `(ERROR)` : ``;
    const return_message = `${script_name}: ${error_label} ${message}`;
    console.log(return_message);
    if (error) return callback(new Error(return_message));
  }
}

Change Password スクリプト

Change Password スクリプト は、Auth0 Dashboard または Auth0 Management API からパスワード変更ワークフローが開始された際に、外部データベース内のユーザーのパスワードを更新する実行可能関数を実装します。

async function changePassword(user, newPassword, context, callback) {
  log(`Script started.`);
  log(`Requesting an Access Token from "${configuration.auth0_domain}".`);
  let accessToken = await getAccessToken();
  if (!accessToken.access_token) return log(`Failed to get an Access Token from "${configuration.auth0_domain}".`, true);
  accessToken = accessToken.access_token;
  log(`The Access Token is available. Searching for user "${user}" in "${configuration.source_database}" database.`);
  user = user.toLowerCase();
  const searchQuery = encodeURI(`identities.connection:"${configuration.source_database}"+AND+(email:${user} OR username:${user})`);
  var options = {
    method: `GET`,
    url: `https://${configuration.auth0_domain}/api/v2/users?q=${searchQuery}`,
    headers: {
      Authorization: `Bearer ${accessToken}`,
    }
  };
  request(options, function (error, response) {
    if (error) return log(`Cannot connect to "${configuration.source_database}" database.`, true);
    let search_results = JSON.parse(response.body);
    if (search_results.length > 0) {
      log(`A user "${user}" is found in "${configuration.source_database}" database.`);
      const user_id = search_results[0].user_id.toString();
      log(`Attempting to change password for user "${user_id}" in "${configuration.source_database}" database.`);
      const options = {
        method: `PATCH`,
        url: `https://${configuration.auth0_domain}/api/v2/users/${user_id}`,
        headers: {
          Authorization: `Bearer ${accessToken}`,
          "Content-Type": `application/x-www-form-urlencoded`
        },
        form: {
          password: newPassword,
        },
        json: true
      };
      request(options, function (error, response) {
        if (error) return log(`Cannot connect to "${configuration.source_database}" database.`, true);
        switch (response.statusCode) {
          case 200:
            log(`The user "${user}" password successfully changed in "${configuration.source_database}" database.`);
            return callback(null, true);
          default:
            return log(`Failed to change password for "${user}"  in "${configuration.source_database}" database. Error: "${response.statusCode}, ${response.body.message}"`, true);
        }
      });
    } else {
      log(`A user "${user}" is not found in "${configuration.source_database}" database. Unable to change password.`, true);
    }
  });
  /* -- クライアントクレデンシャルでアクセストークンを取得 -- */
  async function getAccessToken() {
    var options = {
      method: `POST`,
      url: `https://${configuration.auth0_domain}/oauth/token`,
      headers: {
        "Content-Type": `application/x-www-form-urlencoded`,
      },
      form: {
        grant_type: `client_credentials`,
        client_id: configuration.client_id,
        client_secret: configuration.client_secret,
        audience: `https://${configuration.auth0_domain}/api/v2/`
      },
      json: true
    };
    return new Promise(function (resolve) {
      request(options, function (error, response) {
        resolve(error || response.body);
      });
    });
  }
  /* -- ログ記録 -- */
  function log(message, error = false) {
    const script_name = `CHANGE PASSWORD`;
    const error_label = error ? `(ERROR)` : ``;
    const return_message = `${script_name}: ${error_label} ${message}`;
    console.log(return_message);
    if (error) return callback(new Error(return_message));
  }
}

メールアドレス変更スクリプト

Change Email スクリプトは、ユーザーがメールアドレスまたはその確認ステータスを変更した際に、ユーザーのメールアドレスを更新する実行可能な関数を実装します。 このスクリプトは Auth0 Dashboard では利用できません。Management API の Update a connection エンドポイントを呼び出し、options.customScripts.change_email プロパティを指定する必要があります。

async function changeEmail(user, newEmail, verified, callback) {
  log(`Script started.`);
  log(`Requesting an Access Token from "${configuration.auth0_domain}".`);
  let accessToken = await getAccessToken();
  if (!accessToken.access_token) return log(`Failed to get an Access Token from "${configuration.auth0_domain}".`, true);
  accessToken = accessToken.access_token;
  log(`The Access Token is available. Searching for user "${user}" in "${configuration.source_database}" database.`);
  user = user.toLowerCase();
  const searchQuery = encodeURI(`identities.connection:"${configuration.source_database}"+AND+(email:${user} OR username:${user})`);
  var options = {
    method: `GET`,
    url: `https://${configuration.auth0_domain}/api/v2/users?q=${searchQuery}`,
    headers: {
      Authorization: `Bearer ${accessToken}`,
    }
  };
  request(options, function (error, response) {
    if (error) return log(`Cannot connect to "${configuration.source_database}" database.`, true);
    let search_results = JSON.parse(response.body);
    if (search_results.length > 0) {
      log(`A user "${user}" is found in "${configuration.source_database}" database.`);
      const user_id = search_results[0].user_id.toString();
      log(`Attempting to change email / verified status for user "${user_id}" in "${configuration.source_database}" database.`);
      const options = {
        method: `PATCH`,
        url: `https://${configuration.auth0_domain}/api/v2/users/${user_id}`,
        headers: {
          Authorization: `Bearer ${accessToken}`,
          "Content-Type": `application/x-www-form-urlencoded`
        },
        form: {
          email: newEmail,
          email_verified: verified || false
        },
        json: true
      };
      request(options, function (error, response) {
        if (error) return log(`Cannot connect to "${configuration.source_database}" database.`, true);
        switch (response.statusCode) {
          case 200:
            log(`The user "${user}" email / verified status successfully changed in "${configuration.source_database}" database.`);
            return callback(null, true);
          default:
            return log(`Failed to change email / verified status for "${user}"  in "${configuration.source_database}" database. Error: "${response.statusCode}, ${response.body.message}"`, true);
        }
      });
    } else {
      log(`A user "${user}" is not found in "${configuration.source_database}" database. Unable to change email / verified status.`, true);
    }
  });
  /* -- クライアントクレデンシャルによるアクセストークンの取得 -- */
  async function getAccessToken() {
    var options = {
      method: `POST`,
      url: `https://${configuration.auth0_domain}/oauth/token`,
      headers: {
        "Content-Type": `application/x-www-form-urlencoded`,
      },
      form: {
        grant_type: `client_credentials`,
        client_id: configuration.client_id,
        client_secret: configuration.client_secret,
        audience: `https://${configuration.auth0_domain}/api/v2/`
      },
      json: true
    };
    return new Promise(function (resolve) {
      request(options, function (error, response) {
        resolve(error || response.body);
      });
    });
  }
  /* -- ログ記録 -- */
  function log(message, error = false) {
    const script_name = `CHANGE EMAIL`;
    const error_label = error ? `(ERROR)` : ``;
    const return_message = `${script_name}: ${error_label} ${message}`;
    console.log(return_message);
    if (error) return callback(new Error(return_message));
  }
}

詳細情報