> ## Documentation Index
> Fetch the complete documentation index at: https://translations.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

> 認証トランザクションが完了する前に、post-login Actions を使用してユーザーをリダイレクトする方法を学びます。

# Actions を使用したリダイレクト

認証トランザクションが完了する前に、post-login Actions を使用してユーザーをリダイレクトできます。これにより、標準のログインフォームだけでは完結しない、追加のユーザー操作を伴うカスタム認証フローを実装できます。

リダイレクトは、Auth0 でカスタムの [多要素認証 (MFA)](/docs/ja-jp/secure/multi-factor-authentication) を行うためによく使用されますが、次のような用途にも利用できます。

* カスタムのプライバシーポリシーへの同意取得、利用規約の提示、データ開示フォームの表示を行う。
* 追加で必要なプロファイルデータを、安全に一度だけ収集する。
* リモートの Active Directory ユーザーがパスワードを変更できるようにする。
* 不明な場所からログインしたユーザーに、追加の本人確認を求める。
* 初回のサインアップ時に提供された情報に加えて、ユーザーに関する詳細情報を収集する。

<div id="overview">
  ## 概要
</div>

大まかには、Redirect Action は次のように動作します。

1. Action が URL へのリダイレクトを発行します。
2. その Action の実行が完了すると、Actions パイプラインは中断されます。
3. ユーザーは `state` パラメーターとともにその URL にリダイレクトされます。
4. 外部フローが完了すると、外部サイトは `state` パラメーターとともにユーザーを `/continue` エンドポイントにリダイレクトします。
5. Actions パイプラインは、リダイレクトを呼び出した同じ Action から再開されます。

<div id="start-a-redirect">
  ## リダイレクトを開始する
</div>

以下のように `api.redirect.sendUserTo()` 関数を呼び出します。

```javascript lines theme={null}
/**
* @param {Event} event - ユーザーおよびログイン時のコンテキストに関する詳細情報。
* @param {PostLoginAPI} api - ログインの動作を変更するために使用できるメソッドを持つインターフェース。
*/
exports.onExecutePostLogin = async (event, api) => {
  api.redirect.sendUserTo("https://my-app.exampleco.com");
};
```

Actions はこの Action の実行を完了した後、Actions パイプラインを中断し、ユーザーを `https://my-app.exampleco.com` にリダイレクトします。つまり、リダイレクトを呼び出した Action の後に実行される post-login トリガーにバインドされている Actions は、認証フローが再開されるまで実行されません。Redirect Rules に慣れている場合は、これが Redirect Actions と Redirect Rules の重要な違いであることに注意してください。

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">
  Redirect Rules とは異なり、Redirect Actions はリダイレクトが発行されると Actions パイプラインを中断し、認証フローが再開されると、リダイレクトを発行した同じ Action から再開されます。
</Callout>

Action の実行が完了すると、Auth0 は `api.redirect.sendUserTo()` 関数で指定された URL にユーザーをリダイレクトします。Auth0 はその URL に `state` パラメーターも渡します。例:

`https://my-app.exampleco.com/?state=abc123`

認証トランザクションを再開するには、リダイレクト URL から `state` パラメーターを取得し、それを Auth0 に送り返す必要があります。state は、[クロスサイトリクエストフォージェリ (CSRF) 攻撃](/docs/ja-jp/secure/security-guidance/prevent-threats)を防ぐために使われる opaque な値です。

<div id="resume-the-authentication-flow">
  ## 認証フローを再開する
</div>

リダイレクト後、ユーザーを `/continue` エンドポイントにリダイレクトし、受け取った `state` パラメーターを URL に含めて認証を再開します。元の `state` を `/continue` エンドポイントに返送しないと、Auth0 はログイントランザクションのコンテキストを失い、ユーザーは `invalid_request` エラーのためログインできなくなります。

たとえば、次のようになります。

`https://{yourAuth0Domain}/continue?state=THE_ORIGINAL_STATE`

この例では、`THE_ORIGINAL_STATE` は Auth0 が生成し、リダイレクト URL に送信した値です。たとえば、Action が `https://my-app.exampleco.com/` にリダイレクトする場合、Auth0 は `https://my-app.exampleco.com/?state=abc123` のようなリダイレクト URL を使用するため、`abc123` が `THE_ORIGINAL_STATE` になります。認証トランザクションを再開するには、次の URL にリダイレクトします。

`https://{yourAuth0Domain}/continue?state=abc123`

ユーザーが `/continue` エンドポイントにリダイレクトされると、Actions パイプラインは、リダイレクトを呼び出した同じ Action で `onContinuePostLogin` 関数を呼び出して再開されます。リダイレクトを正しく機能させるには、リダイレクトを呼び出したのと同じ Action に、次のシグネチャを持つ関数が必要です。

```javascript lines theme={null}
/**
* @param {Event} event - ユーザーと、そのユーザーがログインしているコンテキストに関する詳細。
* @param {PostLoginAPI} api - ログインの動作を変更するために使用できるメソッドを持つインターフェース。
*/
exports.onExecutePostLogin = async (event, api) => {
  api.redirect.sendUserTo("https://my-app.exampleco.com");
};

/**
* @param {Event} event - ユーザーと、そのユーザーがログインしているコンテキストに関する詳細。
* @param {PostLoginAPI} api - ログインの動作を変更するために使用できるメソッドを持つインターフェース。
*/

exports.onContinuePostLogin = async (event, api) => {
}
```

<div id="pass-data-to-the-external-site">
  ## 外部サイトにデータを渡す
</div>

外部サイトにデータを渡すには、転送中に改ざんされていないことをアプリケーション側で確実に検証できるよう、そのデータを署名付きの[JWT](/docs/ja-jp/secure/tokens/json-web-tokens)にエンコードすることをお勧めします。Actions では、これを `api.redirect.encodeToken` 関数と `api.redirect.sendUserTo` 関数で実現できます。

```javascript lines expandable theme={null}
/**
* @param {Event} event - ユーザーおよびログイン時のコンテキストに関する詳細情報。
* @param {PostLoginAPI} api - loginの動作を変更するために使用できるメソッドを持つインターフェース。
*/
exports.onExecutePostLogin = async (event, api) => {
  const yourDomain = event.secrets.YOUR_AUTH0_DOMAIN || event.request.hostname

  // 署名付きセッショントークンを作成する
  const token = api.redirect.encodeToken({
    secret: event.secrets.MY_REDIRECT_SECRET,
    expiresInSeconds: 60, 
    payload: {
      // トークンに追加するカスタムクレーム
      email: event.user.email,
      externalUserId: 1234,
      continue_uri: `https://${yourDomain}/continue`
    },
  });

  // メールアドレスを含む `session_token` クエリ文字列
  // パラメーターを付与して、ユーザーを
  // https://my-app.exampleco.com に送信する。
  api.redirect.sendUserTo("https://my-app.exampleco.com", {
    query: { session_token: token }
  });
}
```

上記のコードは、リダイレクトで使用される URL に `session_token` クエリ文字列パラメーターを追加します (Auth0 によって自動的に追加される `state` パラメーターに加えて) 。このトークンには、次の情報が含まれます。

| トークン要素           | 説明                                                                                              |
| ---------------- | ----------------------------------------------------------------------------------------------- |
| `sub`            | ユーザーの Auth0 `user_id`。                                                                          |
| `iss`            | Auth0 テナントのドメインのホスト名 (例: `example.auth0.com`) 。                                                 |
| `exp`            | `expiresInSeconds` パラメーターで指定する有効期限 (秒単位) 。トークンの再利用を防ぐため、できるだけ短く設定してください。デフォルトは 900 秒 (15 分) です。 |
| `ip`             | 認証リクエストの送信元 IP アドレス。                                                                            |
| `email`          | `payload.email` パラメーターで指定した値を持つカスタムクレーム。                                                        |
| `externalUserId` | `payload.externalUserId` パラメーターで指定した値を持つカスタムクレーム。                                               |
| `signature`      | 上記で指定したシークレットを使用して、トークンは HS256 アルゴリズムで署名されます。                                                   |

<div id="ensure-the-token-has-not-been-tampered-with">
  ### token が改ざんされていないことを確認する
</div>

外部システムでは、この token が転送中に改ざんされていないことを検証する必要があります。そのため、リモートシステムでは、token の署名が有効であること、また必要に応じて、外部システム内の session が token の `sub` クレーム に含まれる Auth0 ユーザーと同一ユーザーのものであることを確認する必要があります。

<div id="pass-data-back-to-auth0">
  ## データを Auth0 に返す
</div>

ユーザーが外部サイトでカスタムフローを完了したら、`/continue` エンドポイントにリダイレクトする必要があります。状況によっては、そのユーザーの認証や <Tooltip tip="認可フロー: OAuth 2.0 フレームワークで規定された認可グラント（またはワークフロー）。" cta="用語集を見る" href="/docs/ja-jp/glossary?term=authorization+flow">認可フロー</Tooltip> に影響を与えるため、データを Auth0 に返したい場合があります (たとえば、CAPTCHA チェックやカスタム <Tooltip tip="多要素認証（MFA）: SMS で送信されるコードなど、ユーザー名とパスワードに加えて認証要素を使用するユーザー認証プロセス。" cta="用語集を見る" href="/docs/ja-jp/glossary?term=MFA">MFA</Tooltip> を実装している場合) 。

<div id="use-app-metadata-where-possible">
  ### 可能であればアプリのメタデータを使用する
</div>

可能であれば、リモートシステムでは [Auth0 Management API](https://auth0.com/docs/api/management/v2/) を使用して、Auth0 ユーザープロファイルにカスタム情報をアプリのメタデータとして保存するようにしてください。Auth0 Action フローが再開されると、この情報は `event.user.app_metadata` オブジェクトで利用できるようになります。この方法なら、機密情報をフロントチャネル経由で Auth0 に渡さずに済みます。

<div id="be-selective-when-storing-data-on-the-auth0-user-profile">
  ### Auth0 ユーザープロファイルに保存するデータは必要最小限にしてください
</div>

Auth0 プロファイルに過剰なデータを保存するのは避けてください。これらのデータは、認証および認可のために使用することを想定しています。Auth0 のメタデータ機能と検索機能は、マーケティング調査のように、検索や更新が高頻度で発生する用途向けには設計されていません。このような目的で Auth0 を使用すると、システムのスケーラビリティやパフォーマンスに問題が生じる可能性が高くなります。

アプリケーションで重要なユーザーデータにアクセスする必要がある場合は、そのデータは外部システムに保存し、必要に応じてバックエンドシステムが取得できるよう、Auth0 には外部キー (user ID) のみを保存する方法が推奨されます。

<div id="send-data-on-the-front-channel">
  ## フロントチャネルでデータを送信する
</div>

フロントチャネルで情報をやり取りすると、<Tooltip tip="Bad Actors: ビジネスや環境に脅威をもたらし、危害を加える意図を持つ存在（個人または集団）。" cta="用語集を見る" href="/docs/ja-jp/glossary?term=bad+actors">攻撃者</Tooltip> に狙われる余地が広がります。フロントチャネルで情報を送信する必要がある場合は、次のガイダンスを参考にしてください。

<div id="pass-information-back-to-the-action">
  ### 情報を Action に渡す
</div>

機密情報を Auth0 に渡すには、署名付きのセッショントークンを使用する必要があります。このトークンは、次のコードを使って Action 内で簡単に検証できます。

```javascript lines theme={null}
/**
 * @param {Event} event - ユーザーとログインのコンテキストに関する詳細情報。
 * @param {PostLoginAPI} api - loginの動作を変更するために使用できるメソッドを持つインターフェース。
 */
exports.onContinuePostLogin = async (event, api) => {
  const payload = api.redirect.validateToken({
    secret: event.secrets.PRECONFIGURED_SECRET,
    tokenParameterName: 'my_token',
  });

  // tokenにエンコードされたデータを使用する（例）: 
  api.idToken.setCustomClaim('color', payload.favorite_color);
}
```

トークンは、次の点を満たしていることを確認するために検証されます。

* 署名が有効であること。
* トークンの有効期限が切れていないこと。
* トークン内の `state` クレームが、リダイレクトの一部として使用される `state` パラメーターと一致すること。

| Token Element | Description                                                            |
| ------------- | ---------------------------------------------------------------------- |
| `sub`         | ユーザーの Auth0 `user_id`。                                                 |
| `iss`         | リダイレクト先のアプリケーション。                                                      |
| `exp`         | トークンの再利用を防ぐため、できるだけ短くする必要があります。                                        |
| `state`       | リダイレクトの一部としてリモートサイトに送信される state パラメーター。リプレイ攻撃を防ぐため、これをトークンに含める必要があります。 |
| `other`       | その他のカスタムクレームは、上記のコードで `payload` として公開されます。                             |
| `signature`   | トークンは HS256 アルゴリズムで署名する必要があります。                                        |

リプレイ攻撃を防ぐため、トークンは `/continue` エンドポイントに POST リクエストを送信して Auth0 に返す必要があります。コード内の `tokenParameterName` オプションを使用すると、トークンを含むフィールド名を指定できます。

<div id="custom-authentication-methods">
  ## 独自の認証方法
</div>

ログイン パイプラインでリダイレクトが正常に完了すると、Actions はユーザーのセッションに独自の認証方法イベントを記録できます。`event.authentication.methods` 配列には、ユーザーのブラウザーセッションの間、この独自の認証方法のエントリが保持されます。この配列内の各エントリには、その認証方法が記録された時刻を示すタイムスタンプがあります。

必要な独自の認証方法が `event.authentication.methods` 配列に存在しない場合や、そのエントリが古すぎる場合は、カスタム Action でリダイレクトをトリガーできます。

`api.redirect.sendUserTo()` を使用すると、独自の認証方法を実装するページにユーザーを遷移させることができます。`exports.onContinuePostLogin` ハンドラー内で `api.authentication.recordMethod()` を使用すると、完了した認証方法の記録をユーザーのセッションに保存できます。

`event.authentication.methods` 配列に保存される記録には、`api.authentication.recordMethod()` で選択した URL に一致する `name` プロパティが含まれます。ここで記録された URL を使うと、現在のトランザクションで完了した認証方法を確認し、独自の認証方法がすでに完了しているかどうかを判断できます。

ワークフローによっては、ユーザーのセッションの有効期間中、独自の認証方法を定期的に再実行する必要がある場合があります。たとえば、独自の MFA シナリオでは、一定時間経過後にユーザーの本人確認を再度求める必要が生じることがあります。

次の例では、既存の記録のタイムスタンプを比較して、独自の認証方法をいつ再実行するかを判断しています。

```javascript lines expandable theme={null}
const CUSTOM_METHOD_URL = "https://path.to.prompt";
const PROMPT_TTL = 1000 * 60 * 60 * 24; // 24h

/**
 * Handler that will be called during the execution of a PostLogin flow.
 *
 * @param {Event} event - Details about the user and the context in which
 * they are logging in.
 * @param {PostLoginAPI} api - Interface whose methods can be used to
 * change the behavior of the login.
 */
exports.onExecutePostLogin = async (event, api) => {
  // Search authentication method records for an entry representing our
  // custom method.
  const methodRecord = event.authentication?.methods.find((record) =>
    validateCustomRecord(record, CUSTOM_METHOD_URL, PROMPT_TTL)
  );

  if (!methodRecord) {
    const sessionToken = api.redirect.encodeToken({
      payload: {
        user_id: event.user.user_id,
      },
      secret: event.secrets.SESSION_TOKEN_SECRET,
    });

    // We didn't find a valid record, so we send the user to the
    // URL that implements the custom method with the signed
    // data we encoded in `sessionToken`.
    api.redirect.sendUserTo(CUSTOM_METHOD_URL, {
      query: { session_token: sessionToken },
    });
  }
};

/**
 * 外部リダイレクト後にこの Action が再開される際に呼び出されるハンドラー。
 * onExecutePostLogin 関数がリダイレクトを実行しない場合、この関数は無視して構いません。
 *
 * @param {Event} event - ユーザーおよびログイン時のコンテキストに関する詳細。
 * @param {PostLoginAPI} api - ログインの動作を変更するために使用できるメソッドを持つインターフェース。
 */
exports.onContinuePostLogin = async (event, api) => {
  const payload = api.redirect.validateToken({
    secret: event.secrets.SESSION_TOKEN_SECRET,
    tokenParameterName: "session_token",
  });

  if (!validateSessionToken(payload)) {
    return api.access.deny("Unauthorized");
  }

  // Record the completion of our custom authentication method.
  // THIS NEW API IS ONLY AVAILABLE IN `onContinuePostLogin`.
  api.authentication.recordMethod(CUSTOM_METHOD_URL);
};

function validateCustomRecord(record, url, ttl) {
  if (!record) {
    // No record means it isn't valid.
    return false;
  }

  if (record.url !== url) {
    // This isn't a record of our custom method.
    return false;
  }

  // Timestamps are rendered as ISO8601 strings.
  const timestamp = new Date(record.timestamp);

  // The record is valid if it was recorded recently enough.
  return timestamp.valueOf() >= Date.now() - ttl;
}

function validateSessionToken(payload) {
  // Custom validation logic for the data returned by the
  // custom method goes here.
  return true;
}
```

`api.authentication.recordMethod()` API は、`exports.onContinuePostLogin` ハンドラーでのみ利用できます。これにより、リダイレクトの完了後にカスタムメソッドを記録することで、ログイン時の不正利用の可能性を防げます。

<div id="restrictions-and-limitations">
  ## 制約と制限
</div>

Redirect Actions は以下では機能しません。

* [リソース所有者エンドポイント](https://auth0.com/docs/api/authentication/reference#resource-owner)
* [パスワード交換](/docs/ja-jp/get-started/authentication-and-authorization-flow/resource-owner-password-flow)
* [リフレッシュトークン交換](/docs/ja-jp/secure/tokens/refresh-tokens)

<div id="resource-owner-endpoint">
  ### リソース所有者エンドポイント
</div>

<Tooltip tip="リソース所有者: 保護されたリソースへのアクセスを許可できるエンティティ（ユーザーやアプリケーションなど）。" cta="用語集を表示" href="/docs/ja-jp/glossary?term=Resource+Owner">リソース所有者</Tooltip>パスワードフローで Authentication API の [Get Token](https://auth0.com/docs/api/authentication#resource-owner-password) エンドポイントを呼び出す場合、Redirect Actions は使用できません。そもそもユーザーはリダイレクトフローの途中にいないため、Action でユーザーをリダイレクトすることはできません。

<div id="flows-where-promptnone">
  ### `prompt=none` のフロー
</div>

`prompt=none` の目的は、ユーザーに入力を求める状況を一切発生させないことにあるため、どのようなリダイレクトでも `error=interaction_required` になります。

Actions は認証セッションの作成後に実行されるため、特定の条件下でトークンへのアクセスをブロックしようとするリダイレクトルールがある場合は、`prompt=none` を使用できません (たとえば、カスタム MFA やログイン時の CAPTCHA など) 。

`prompt=none` を使用する場合、トークンへのアクセスをブロックしつつ、リダイレクト Action を回避できるようなリダイレクトフローは作成できません。試行が失敗した後でも、ユーザーは単に `prompt=none` を付けて再度呼び出すだけでトークンを取得できてしまうためです。これは、最初に Actions が失敗していても、認証セッション自体はすでに作成されているからです。

<div id="refresh-tokens">
  ### リフレッシュトークン
</div>

<Tooltip tip="リフレッシュトークン: ユーザーに再度ログインを求めることなく、新しいアクセストークンを取得するために使用されるトークン。" cta="用語集を見る" href="/docs/ja-jp/glossary?term=refresh+token">リフレッシュトークン</Tooltip>を使用するには、Authentication API の [Get Token](https://auth0.com/docs/api/authentication#refresh-token) エンドポイントへのバックチャネル呼び出しが必要になるため、リダイレクトを試みた場合、これも失敗します。

ログインに対する制限が実際に適用されたことを安全に検証するのは困難です。コンテキスト内には一貫したセッション ID が存在せず、このユーザーが MFAチャレンジを通過したかどうかといった、セッションに関連する情報を収集するために利用できません。したがって、`prompt=none` はまったく使用できません。

Action で `api.redirect.sendUserTo()` が呼び出されるたびに、`prompt=none` が渡されていた場合、認可は `error=interaction_required` で失敗します。しかし、Actions が失敗してもユーザーのセッションは作成されるため、ユーザーがリダイレクトチャレンジを通過したことを信頼できず、その結果、トークンを取得する手段として `prompt=none` を使用できません。

この特定のケースでは、リフレッシュトークンの生成にそれらのチャレンジが必要であれば、ユーザーがチャレンジを通過したことを確実に確認できるため、リフレッシュトークンのみを使用することを推奨します。

<div id="learn-more">
  ## 詳細はこちら
</div>

* [post-login Action トリガーでユーザーメタデータを管理する](/docs/ja-jp/manage-users/user-accounts/metadata/manage-user-metadata)
