> ## Documentation Index
> Fetch the complete documentation index at: https://docs-dev-fix-docs-5528-php-updates.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# RulesからActionsに移行する

> 既存のAuth0 HooksコードをAuth0 Actionsコードに移行する方法を学びます。

既存のルールをアクションに変換する場合は、新しいアクションをログインフローのログイン後(`post-login`)トリガーに関連付ける必要があります。以下の手順に従い、アクションを元のルールと同じ順序にしておくと、機能は同じになります。

## 移行を計画する

Post-Loginアクションは既存のルールの後に実行されるため、Dashboardでルールを一度に1つずつ変換することも、 <Tooltip data-tooltip-id="react-containers-DefinitionTooltip-0" href="/docs/ja-jp/glossary?term=management-api" tip="Management API: 顧客が管理タスクを実行できるようにするための製品。" cta="用語集の表示">Management API</Tooltip>を使用して一度にすべてを変換することもできます。

コードを変換してから、アクションをアクティブにし、ルールを非アクティブにする必要があります。アクションの有効化とルールの無効化は、連続してすばやく実行できますが、順序によっては、両方が実行されない、またはどちらも実行されない時間が短期間発生する場合があります。

このため、パイプラインを段階的に移行することをお勧めします。ルールコードの一部をアクションコードに変換し、ステージング環境でテストしてから、一度に1つずつライブに移行します。アクティブなルールはデプロイされたアクションの前に実行されるため、ルールパイプラインの最後から開始して逆方向に作業すると、アクションで他のロジックを構築およびテストするときに、一部のロジックをルールに保持したままにすることができます。

<Card title="移行を計画するときのヒント">
  * アクションとルールを1対1にして、機能のオン・オフやテストをひとまとめに実行できるようにします。
  * ユーザーメタデータにフラグを使って、コストがかかる操作や1回限りの操作が重複しないようにします。
  * Rulesのパイプラインの最後から始めて、逆方向に作業します。アクティブなRulesはアクションのデプロイ前に実行されるため、構築の際にはRules内にいくつかのロジックを維持させて、他のロジックをActionsでテストすることができます。
  * 変更は、影響やトラフィックが最も少ない時間帯や時期に行います。
  * 移行期間が無効なログインや保護の欠落に繋がるようであれば、一時的に[ログインページをカスタマイズ](/docs/ja-jp/customize)して、ログインを停止することを検討します。
  * 移行のスクリプトを作成し、一括または繰り返してテストと実装が行えるように、[Auth0 Deploy CLI](/docs/ja-jp/deploy-monitor/deploy-cli-tool)の使用を考慮します。
</Card>

## 制限事項を理解する

アクションはルールでできることの大部分を処理できますが、移行を開始する前にいくつかの制限事項に注意する必要があります（注：フックとアクションはどちらも移行中に実行できます）。

* アクションには、ルールの場合のように、[Management APIのアクセストークン](/docs/ja-jp/customize/rules/use-management-api)や[グローバル`auth0`オブジェクト](/docs/ja-jp/rules-best-practices/rules-environment-best-practices)へのアクセスは提供されません。Management API呼び出しを引き続き行う方法については、「[コードの変換](#convert-code)」セクションを参照してください。

すべての制限事項については、「[Actionsの制限事項](/docs/ja-jp/customize/actions/limitations)」を参照してください。

## コードを変換する

ルールをアクションに変換するには、ルール固有のコードをアクションコードに置き換える必要があります。このセクションでは、機能するルールを同等のアクションに変換するためのタスクについて説明します。

<Card title="コードを変換するときのヒント">
  * 一般的に、Actionsの`event` オブジェクトについて、Rulesの`user`と`context`オブジェクトの読み取り専用プロパティを確認します。`api`オブジェクトの機能について、Actionsがシステムに及ぼす副次的な影響（ログインの失敗、ユーザーメタデータの更新など）を確認します。
  * コードを書くときは、Auth0 DashboardのActions Code Editorを使います。エラーがハイライトされたり、オートコンプリート機能によって提案が自動入力されたりするので、便利です。
  * 稼働させる前に、[新しいActionsのテスト](/docs/ja-jp/customize/actions/test-actions)を[ステージング環境やテスト環境](/docs/ja-jp/get-started/auth0-overview/create-tenants/set-up-multiple-environments)で念入りに行います。
</Card>

### ルールコードを新しいアクションにコピーする

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">
  ルールのコードを新しいアクションにコピーし、Auth0 DashboardのActionsコードエディターで使用することをお勧めします。コードにある未解決の問題が特定できます。
</Callout>

1. 運用テナントにログインし、変換元となるルールのコードをコピーします。
2. 非運用テナントに切り替えて、[［Auth0 Dashboard］ > ［Actions（アクション）］ > ［Library（ライブラリ）］](https://manage.auth0.com/#/select-tenant?path=/actions/library)に移動します。
3. **［Build Custom（カスタムの構築）］** を選択した後、

   * 変換するルールの名前と一致するアクションの **名前** を入力します。
   * **トリガー** を見つけて、 **ログイン/ログイン** 後を選択します。
   * **［Runtime（ランタイム）］** で、 **［Node 22］** を選択します。
   * **［Create（作成）］** を選択します。
4. アクションコードエディターのコードブロックで、エクスポートされた`onExecutePostLogin`関数の下に変換するルールコードを貼り付けます。
5. コードを関数に移動するときに、この記事で後述している変更を加えます。

### 関数宣言を変更する

ルールは、`ユーザー`、`コンテキス`ト、および`コールバック`パラメータを持つ単純な宣言済み関数を使用しますが、アクションは特定の名前にエクスポートされた関数を使用します。以下の変更を加えます。現在のところ、表示されるエラーは無視してください。

**変更前**

```js lines theme={null}
async function myRulesFunction(user, context, callback) {
    // ... additional code
}
```

**変換後**

```js lines theme={null}
exports.onExecutePostLogin = async (event, api) => {
	// ... additional code
};
```

### ユーザーデータへのアクセス方法を変更する

ルールでは、ログインするユーザーに関するデータは[`user`オブジェクト](/docs/ja-jp/customize/rules/user-object-in-rules)に保存されます。アクションでは、このデータは[`event`オブジェクト](/docs/ja-jp/customize/actions/explore-triggers/signup-and-login-triggers/login-trigger/post-login-event-object)の`user`プロパティにあります。既存のプロパティの大部分は、この新しい場所でアクセスできます。

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">
  `event`オブジェクトのプロパティで保管・変更されたデータは、他のアクションでは使用できません。
</Callout>

**変更前**

```javascript lines theme={null}
function myRulesFunction(user, context, callback) {
	const userEmail = user.email;
	const userId = user.user_id;

	// This property could be undefined in Rules.
	const userAppMetadata = user.app_metadata || {};

	// ... additional code
}
```

**変換後**

```js lines theme={null}
exports.onExecutePostLogin = async (event, api) => {
	const userEmail = event.user.email;
	const userId = event.user.user_id;

	// This property will never be undefined in Actions.
	const userAppMetadata = event.user.app_metadata;

	// ... additional code
};
```

### コンテキストデータへのアクセス方法を変更する

ルールでは、現在のログインセッションに関するデータは[`context`オブジェクト](/docs/ja-jp/customize/rules/context-object)に保存されます。アクションの場合、このデータは再形成され、[`event`オブジェクト](/docs/ja-jp/customize/actions/explore-triggers/signup-and-login-triggers/login-trigger/post-login-event-object)に移動されました。プロパティの多くはそのまま移行されましたが、わかりやすくするために一部が結合されました。

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">
  `event`オブジェクトのプロパティで保管・変更されたデータは、他のアクションでは使用できません。`context.idToken`や`context.multifactor`など、プロパティにデータを設定することでルールがコア機能をトリガーする場合は、そのようなユースケースについて説明している以下のセクションをお読みください。
</Callout>

**変更前**

```javascript lines theme={null}
function myRulesFunction(user, context, callback) {
	const clientId = context.clientID;
	const clientMetadata = context.clientMetadata || {};

	const connectionId = context.connectionID;
	const connectionMetadata = context.connectionMetadata || {};

	const protocol = context.protocol;

	const tenant = context.tenant;

	// ... additional code
}
```

**変換後**

```js lines theme={null}
exports.onExecutePostLogin = async (event, api) => {
	const clientId = event.client.client_id;
	const clientMetadata = event.client.metadata;

	const connectionId = event.connection.id;
	const connectionMetadata = event.connection.metadata;

	const protocol = event.transaction.protocol;

	const tenant = event.tenant.id;

	// ... additional code
};
```

### 依存関係を変換する

ルールには、`require`ステートメントにバージョン番号を含めることを要求する方法で依存関係が含まれます。アクションでは、より標準的なCommonJS構文が使用され、コードエディターの外部でバージョンを示す必要があります。

ルールでは、特定のパッケージの特定のバージョンのみが許可され、新しいパッケージとバージョンを追加するにはAuth0への要求が必要です。アクションでは、`npm`レジストリで利用可能な任意のパッケージを要求できます。

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">
  `npm`モジュールが最新バージョンでないなら、今こそアップデートする絶好の機会です！
</Callout>

1. ルールコード内で`require`ステートメントを検索します。
2. バージョン番号を削除しますが、これらの番号はメモしておいてください。
3. 依存関係が[コアNodeJSモジュール](https://github.com/nodejs/node/tree/master/lib)でない場合は、「[初めてアクションを作成する](/docs/ja-jp/customize/actions/write-your-first-action)」の「依存関係を追加する」セクションの手順に従って依存関係を追加してください。依存関係がコアNodeJSモジュールである場合は、追加する必要はありません。
4. 見つかった`require`ステートメントを`function`宣言の外に移動します:

**変更前**

```javascript lines theme={null}
function myRulesFunction(user, context, callback) {
	const dependency = require("dependency@1.2.3");

	// ... additional code
}
```

**変換後**

```javascript lines theme={null}
const dependency = require("dependency"); // v1.2.3
exports.onExecutePostLogin = async (event, api) => {
	// ... additional code
};
```

### コールバックを変換する

ルールの処理が完了したら、`callback()`関数を呼び出して、ログインに失敗した場合はエラーを渡す必要があります。逆に、アクションは成功時に返したり、ログインに失敗した場合はメッセージとともに`api`メソッドを呼び出したりできます。ルール内の`callback()`のすべてのインスタンスは削除するか、失敗した場合は`api.access.deny()`に置き換える必要があります。ルールとアクションの両方で、特定の条件で処理を停止する必要がある場合は、`return`ステートメントを使用します。

**変更前**

```javascript lines theme={null}
function myRulesFunction(user, context, callback) {
	const userAppMetadata = user.app_metadata || {};
	if (userAppMetadata.condition === "success") {
		// This Rule succeeded, proceed with next Rule.
		return callback(null, user, context);
	}

	if (userAppMetadata.condition === "failure") {
		// This Rule failed, stop the login with an error response.
		return callback(new Error("Failure message"));
	}

	// ... additional code
}
```

**変換後**

```js lines theme={null}
exports.onExecutePostLogin = async (event, api) => {
	if (event.user.app_metadata.condition === "success") {
		// This Action succeeded, proceed with next Action.
		return;
	}

	if (event.user.app_metadata.condition === "failure") {
		// This Action failed, stop the login with an error response.
		return api.access.deny("Failure message");
	}

	// ... additional code
};
```

### シークレットの処理を変更する

ルールでは、構成値をグローバルに設定します。これは、すべてのルールがすべてのシークレット値にアクセスできることを意味します（詳細については、「[ルールの構成を保管する](/docs/ja-jp/customize/rules/configuration)」を参照してください）。アクションでは、個々のアクションごとに構成値を設定します。アクションのコンテキスト外からアクションのシークレット値にアクセスすることはできません。

シークレットをルールからアクションに変換するには：

1. 操作中の特定のアクションに必要な値を保存します。
2. アクション内からアクセスする必要がある値ごとにシークレットを追加します。方法については、「[初めてアクションを作成する](/docs/ja-jp/customize/actions/write-your-first-action)」の「 **シークレットを追加する** 」セクションをお読みください。
3. コードを変換します。

**変更前**

```javascript lines theme={null}
function myRulesFunction (user, context, callback) {
  const { CLIENT_ID, CLIENT_SECRET } = configuration;

  // ... additional code
}
```

**変換後**

```js lines theme={null}
exports.onExecutePostLogin = async (event, api) => {
  const { CLIENT_ID, CLIENT_SECRET } = event.secrets;

  // ... additional code
}
```

ルールの場合と同様に、Auth0は保管時のすべてのシークレット値を暗号化します。

### カスタムクレームをトークンに変換する

ルールとアクションでは共に、カスタムクレームをIDトークンおよびアクセストークンに追加できます。ルールでは、これは`context`オブジェクトのプロパティですが、アクションでは[`api`オブジェクト](/docs/ja-jp/customize/actions/explore-triggers/signup-and-login-triggers/login-trigger/post-login-api-object)のメソッドが使用されます。

**変更前**

```javascript lines theme={null}
function myRulesFunction(user, context, callback) {
	const userAppMetadata = user.app_metadata || {};
	const namespace = "https://namespace/";

	context.idToken[`${namespace}/emp_id`] = userAppMetadata.emp_id;
	context.accessToken[`${namespace}/emp_id`] = userAppMetadata.emp_id;

	// ... additional code
}
```

**変換後**

```js lines theme={null}
exports.onExecutePostLogin = async (event, api) => {
	const namespace = "https://namespace/";

	api.idToken.setCustomClaim(
		`${namespace}/emp_id`, 
		event.user.app_metadata.emp_id
	); 		   

	api.accessToken.setCustomClaim(
		`${namespace}/emp_id`, 
		event.user.app_metadata.emp_id
	);

	// ... additional code
};
```

### 多要素トリガーを変換する

ルールでは、[`context`オブジェクト](/docs/ja-jp/customize/rules/context-object)の`multifactor`プロパティを変更することで、多要素認証をトリガーできます。アクションでは、これは[`api`オブジェクトのメソッド](/docs/ja-jp/customize/actions/explore-triggers/signup-and-login-triggers/login-trigger/post-login-api-object)を使用して実行されます。

**変更前**

```javascript lines theme={null}
function myRulesFunction(user, context, callback) {
	if (user.app_metadata.needs_mfa === true) {
		context.multifactor = { 
			provider: "any", 
			allowRememberBrowser: false,
		};
	}

	// ... additional code
}
```

**変換後**

```js lines theme={null}
exports.onExecutePostLogin = async (event, api) => {
	if (event.user.app_metadata.needs_mfa === true) {
		api.multifactor.enable("any", { allowRememberBrowser: false });
	}

	// ... additional code
};
```

### ユーザーメタデータの更新を変換する

ルール内の`user_metadata`プロパティと`app_metadata`プロパティを更新するには、Management APIの呼び出しが必要であり、[レート制限](/docs/ja-jp/troubleshoot/customer-support/operational-policies/rate-limit-policy/management-api-endpoint-rate-limits)エラーが発生する可能性があります。ただし、アクションは複数のユーザーメタデータの変更を示す方法を提供しますが、Management APIを呼び出すのは1回だけです。

**変更前**

```javascript lines theme={null}
function myRulesFunction(user, context, callback) {
	user.app_metadata = user.app_metadata || {}; 
	user.app_metadata.roles = user.app_metadata.roles || [];
	user.app_metadata.roles.push("administrator"); 

	auth0.users
		.updateAppMetadata(user.user_id, user.app_metadata) 
		.then(() => callback(null, user, context))
		.catch((err) => callback(err));

	// ... additional code
}
```

後続のルールでユーザーメタデータを更新する必要がある場合は、Management APIを個別に呼び出す必要があるため、[レート制限](/docs/ja-jp/troubleshoot/customer-support/operational-policies/rate-limit-policy/management-api-endpoint-rate-limits)に達する可能性が高くなります。

**変換後**

```js lines theme={null}
exports.onExecutePostLogin = async (event, api) => {
	const userRolesUpdated = event.user.app_metadata.roles || [];
	userRolesUpdated.push("administrator"); 

	// Note the two different methods here. 
	api.user.setAppMetadata("roles", userRolesUpdated);
	api.user.setUserMetadata("hasRoles", true);

	// ... additional code
};
```

後続のアクションでユーザーメタデータを更新する必要がある場合は、`api.user.setUserMetadata`または`api.user.setAppMetadata`を呼び出す必要があります。アクションでは、1つまたは複数のアクションにわたってこれらの関数を複数回呼び出すと、フローが完了したときに1つのManagement API呼び出しが行われます。

### 他のManagement API呼び出しを変換する

一般に、ルールやアクションなどの高トラフィックのクリティカルパスからManagement APIを呼び出すことはお勧めしません。拡張ポイントからの呼び出しを含め、すべてのAuth0 APIへの要求には[レート制限](/docs/ja-jp/troubleshoot/customer-support/operational-policies/rate-limit-policy)があり、すべてのログインに対してAPIを呼び出すと、トラフィックが多いときにログインが失敗する可能性があります。

ただし、呼び出しが必要で、それらがレート制限を回避するように構成されている場合は、アクション内からManagement APIを呼び出すことができます。前述の「制限事項を理解する」セクションで説明しているように、アクションにはManagement APIのアクセストークンが提供されないため、アクションを有効にする前にアクセストークンを取得する必要があります。

1. [M2Mアプリケーションを登録し、Management APIに対して認可します](/docs/ja-jp/get-started/auth0-overview/create-applications/machine-to-machine-apps)。
2. アクションに **クライアントID** と **クライアントシークレット** を保存します。
3. [Management APIのアクセストークンを取得します](/docs/ja-jp/secure/tokens/access-tokens/management-api-access-tokens/get-management-api-access-tokens-for-production)。
4. Management APIを呼び出します。

   <Warning>
     Actionsは、実行間でデータを保持できないため、アクセストークンをキャッシュすることができません。Management APIを呼び出す度に認証APIの呼び出しも必要となるため、Management APIの呼び出しは非常にコストのかかる操作です。
   </Warning>

**変更前**

```javascript lines theme={null}
function myRulesFunction(user, context, callback) {
	const ManagementClient = require("auth0@2.9.1").ManagementClient; 
	const managementClientInstance = new ManagementClient({
		// These come from built-in Rules globals
		token: auth0.accessToken, 
		domain: auth0.domain,
	}); 

	managementClientInstance.users.assignRoles(
		{ id: user.user_id }, 
		{ roles: ["ROLE_ID_TO_ADD"] }, 
		(error, user) => {
			if (error) {
				return callback(error);
			}

			// ... additional code
		}
	);
}
```

**変換後**

```javascript lines theme={null}
const auth0Sdk = require("auth0");
exports.onExecutePostLogin = async (event, api) => {
	const ManagementClient = auth0Sdk.ManagementClient;

	// This will make an Authentication API call
	const managementClientInstance = new ManagementClient({
		// These come from a machine-to-machine application
		domain: event.secrets.M2M_DOMAIN,
		clientId: event.secrets.M2M_CLIENT_ID,
		clientSecret: event.secrets.M2M_CLIENT_SECRET,
		scope: "update:users"
	});

	managementClientInstance.users.assignRoles(
		{ id: event.user.user_id }, 
		{ roles: ["ROLE_ID_TO_ADD"]}, 
		(error, user) => {
			if (error) {
				return api.access.deny(error.message);
			}

			// ... additional code
		}
	);
};
```

### リダイレクトを変換する

ルールは、外部ページにログインしているユーザーをリダイレクトし、応答を待つことができます。この場合、リダイレクト前のすべてのルールが2回実行されます。つまり、リダイレクト前に1回と、応答時に1回です。リダイレクトと応答のロジックは通常、同じルールに含まれます。

アクションでは、リダイレクトが発生するとアクションパイプラインが一時停止し、ユーザーが戻ると再開されます。また、エクスポートされたリダイレクトトリガー関数はリダイレクトコールバックとは別のものです。

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">
  あらゆるリダイレクトをアクションで適切に行う方法について、このガイドで説明することはできません。詳細については、「[アクションを使ったリダイレクト](/docs/ja-jp/customize/actions/explore-triggers/signup-and-login-triggers/login-trigger/redirect-with-actions)」をお読みください。
</Callout>

**変更前**

```javascript lines theme={null}
function myRulesFunction(user, context, callback) {
    if (context.protocol === "redirect-callback") {
        // User was redirected to the /continue endpoint
        user.app_metadata.wasRedirected = true;
        return callback(null, user, context);
    } else if (
        context.protocol === "oauth2-password" ||
        context.protocol === "oauth2-refresh-token" ||
        context.protocol === "oauth2-resource-owner"
    ) {
        // User cannot be redirected
        return callback(null, user, context);
    }
    // User is logging in directly
    if (!user.app_metadata.wasRedirected) {
        context.redirect = {
            url: "https://example.com",
        };
        callback(null, user, context);
    }
}
```

**変換後**

```js lines theme={null}
exports.onExecutePostLogin = async (event, api) => {
    api.accessToken.setClaim("https://dev.TLD/wasRedirected", true)
```

### 現在のSSOクライアント参照を変換します

ルールの`context.sso`オブジェクトは、現在のセッションとそれを使用しているクライアントに関する詳細を提供します。詳細については、[ルールのコンテキストオブジェクトプロパティ](/docs/ja-jp/customize/rules/context-object)の`context.sso`エントリを参照してください。同様の情報は、アクションの`event.session`オブジェクトでも入手できます。

**変更前**

```javascript lines theme={null}
function (user, context, callback) {

  const clients = context.sso?.current_clients ?? []; 

  if (clients.length > 0) { 
	context.idToken.clients = clients.join(" "); 
  }

  return callback(null, user, context);
}
```

**変換後**

```js lines theme={null}
exports.onExecutePostLogin = async (event, api) => {
  const clients = event?.session?.clients ?? []; 

  if (clients.length > 0) { 
    api.idToken.setCustomClaim('clients', clients.map(c=> c?.client_id).join(" ")); 
  }
};
```

## 移行を完了する

新しいアクションコードを作成してテストしたら、アクションを有効にし、ルールを無効にする必要があります。これらの2つのタスクは連続してすばやく実行できますが、順序によっては、両方が実行されない、またはどちらも実行されない時間が短期間発生する場合があります。アクティブなルールは導入されたアクションの前に実行されるため、ルールパイプラインの最後から開始して逆方向に作業すると、アクションで他のロジックを構築およびテストするときに、一部のロジックをルールに保持したままにすることができます。
