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

# ルール内でユーザーをリダイレクトする

> ルールを使用してユーザーをリダイレクトし、認証フローをカスタマイズする方法を説明します。カスタマイズ可能な領域の例には、MFA、プライバシーポリシーへの同意、ユーザーデータの収集があります。

export const AuthCodeBlock = ({filename, icon, language, highlight, children}) => {
  const [displayText, setDisplayText] = useState(children);
  const [copyText, setCopyText] = useState(children);
  const wrapperRef = React.useRef(null);
  useEffect(() => {
    let unsubscribe = null;
    function init() {
      if (!window.autorun || !window.rootStore) {
        return;
      }
      unsubscribe = window.autorun(() => {
        let processedChildrenForDisplay = children;
        let processedChildrenForCopy = children;
        for (const [key, value] of window.rootStore.variableStore.values.entries()) {
          const escapedKey = key.replaceAll(/[.*+?^${}()|[\]\\]/g, (String.raw)`\$&`);
          let displayValue = value;
          if (key === "{yourClientSecret}" && value !== "{yourClientSecret}") {
            displayValue = value.substring(0, 3) + "*****MASKED*****";
          }
          processedChildrenForDisplay = processedChildrenForDisplay.replaceAll(new RegExp(escapedKey, "g"), displayValue);
          processedChildrenForCopy = processedChildrenForCopy.replaceAll(new RegExp(escapedKey, "g"), value);
        }
        setDisplayText(processedChildrenForDisplay);
        setCopyText(processedChildrenForCopy);
      });
    }
    if (window.rootStore) {
      init();
    } else {
      window.addEventListener("adu:storeReady", init);
    }
    return () => {
      window.removeEventListener("adu:storeReady", init);
      unsubscribe?.();
    };
  }, [children]);
  useEffect(() => {
    if (!wrapperRef.current) return;
    const originalWriteText = navigator.clipboard.writeText.bind(navigator.clipboard);
    let isOverriding = false;
    const handleClick = e => {
      const button = e.target.closest('[data-testid="copy-code-button"]');
      if (!button || !wrapperRef.current.contains(button)) return;
      isOverriding = true;
      navigator.clipboard.writeText = text => {
        if (isOverriding) {
          isOverriding = false;
          navigator.clipboard.writeText = originalWriteText;
          return originalWriteText(copyText);
        }
        return originalWriteText(text);
      };
      setTimeout(() => {
        if (isOverriding) {
          isOverriding = false;
          navigator.clipboard.writeText = originalWriteText;
        }
      }, 100);
    };
    const wrapper = wrapperRef.current;
    wrapper.addEventListener('click', handleClick, true);
    return () => {
      wrapper.removeEventListener('click', handleClick, true);
      if (navigator.clipboard.writeText !== originalWriteText) {
        navigator.clipboard.writeText = originalWriteText;
      }
    };
  }, [copyText]);
  return <div ref={wrapperRef}>
      <CodeBlock filename={filename} icon={icon} language={language} lines highlight={highlight}>
        {displayText}
      </CodeBlock>
    </div>;
};

<Warning>
  RulesとHooksのサポート終了（EOL）日は**2026年11月18日** であり、**2023年10月16** 日の時点で作成された新しいテナントは使用できなくなります。Hooksが有効な既存のテナントは、サポート終了までHooksを利用できます。

  今後はActionsに移行して、Auth0の機能を拡張することを強くお勧めします。Actionsを使用すると、豊富な情報やインラインドキュメント、パブリック`npm`パッケージにアクセスして、外部統合を使って全体的な拡張エクスペリエンスを強化することができます。Actionsの詳細については、「[Auth0 Actionsの仕組みを理解する](/docs/ja-jp/customize/actions/actions-overview)」をお読みください。

  当社では、移行の参考資料として、[RulesからActionsへの移行](/docs/ja-jp/customize/actions/migrate/migrate-from-rules-to-actions)と[HooksからActionsへの移行](/docs/ja-jp/customize/actions/migrate/migrate-from-hooks-to-actions)に関するガイドを提供しています。また、専用の「[Actionsへの移行](https://auth0.com/extensibility/movetoactions)」ページでは、機能の比較や[Actionsのデモ](https://www.youtube.com/watch?v=UesFSY1klrI)、その他のリソースを掲載して、円滑な移行をサポートしています。

  RulesとHooksの廃止の詳細については、当社のブログ記事「[RulesとHooksの提供終了について](https://auth0.com/blog/preparing-for-rules-and-hooks-end-of-life/)」をお読みください。
</Warning>

認証トランザクションの完了前に、 [Auth0ルール](/docs/ja-jp/customize/rules)を使用してユーザーをリダイレクトすることができます。これによって、カスタム認証フローを実装して、標準のログインフォームにはない追加のユーザー操作に対応できるようになります。リダイレクトルールは一般的に、Auth0でカスタムの多要素認証（<Tooltip data-tooltip-id="react-containers-DefinitionTooltip-0" href="/docs/ja-jp/glossary?term=multifactor-authentication" tip="多要素認証（MFA）: ユーザー名とパスワードに加えて、SMS経由のコードなどの要素を使用するユーザー認証プロセス。" cta="用語集の表示">MFA</Tooltip>）を実行するために使用されますが、以下にも使用できます。

* カスタムのプライバシーポリシーへの同意、利用規約、データ開示のフォーム。
* 追加で必要なプロファイルデータを安全に一度だけ収集する。
* Active Directoryのリモートユーザーがパスワードを変更できるようにする。
* ユーザーが未知の場所からログインする際に、追加で検証を求める。
* サインアップ時にユーザーが提供した以上のユーザー情報を集める。

認証フローごとに、ユーザーを**1回** リダイレクトできます。ユーザーをリダイレクトするルールが1つある場合、後でユーザーをリダイレクトする2つ目のルールを呼び出すことは**できません** 。

詳細については、「[Auth0での多要素認証](/docs/ja-jp/secure/multi-factor-authentication)」をご覧ください。

## リダイレクトを開始して認証を再開する

`context.redirect`プロパティを以下のように設定します。

```javascript lines theme={null}
function (user, context, callback) {
  context.redirect = {
    url: "https://example.com/foo"
  };
  return callback(null, user, context);
}
```

すべてのルールの実行が完了したら、Auth0は`context.redirect.url`プロパティで指定されたURLにユーザーをリダイレクトします。また、Auth0はそのURLで`state`パラメーターも渡します。例：

```lines theme={null}
https://example.com/foo?state=abc123
```

認証トランザクションを再開するには、リダイレクトURLが`state`パラメーターを抽出し、それをAuth0に送り返す必要があります。状態は不透明な値で、[クロスサイトリクエストフォージェリ（CSRF）攻撃](/docs/ja-jp/security/common-threats#cross-site-request-forgery)を防ぐために使用されます。

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

例：

export const codeExample1 = `https://{yourDomain}/continue?state={originalState}`;

<AuthCodeBlock children={codeExample1} language="bash" />

カスタムドメインを使用している場合：

```bash lines theme={null}
https://{yourAuth0CustomDomain}/continue?state={originalState}
```

`THE_ORIGINAL_STATE`はAuth0が生成した値で、リダイレクトURLに送信されます。たとえば、ルールが`https://example.com/foo`にリダイレクトする場合、Auth0は`https://example.com/foo?state=abc123`に類似したリダイレクトURLを使用します。つまり、`abc123`が`THE_ORIGINAL_STATE`です。認証トランザクションを再開するには、以下にリダイレクトします。

export const codeExample2 = `https://{yourDomain}/continue?state=abc123`;

<AuthCodeBlock children={codeExample2} language="bash" />

ユーザーが`/continue`エンドポイントにリダイレクトされた場合：

* **すべてのルールが再度実行されます** が、`context.redirect`は無視され、認証を続行することができます。
* ユーザーオブジェクトへの変更は、`/continue` エンドポイントを呼び出す前のリダイレクト中に行われます。たとえば、Auth0 <Tooltip data-tooltip-id="react-containers-DefinitionTooltip-0" href="/docs/ja-jp/glossary?term=management-api" tip="Management API: 顧客が管理タスクを実行できるようにするための製品。" cta="用語集の表示">Management API</Tooltip>を介した更新は、トランザクションの続行後に使用できます。

## 再開したログインを確認する

ユーザーが開始したログインと再開したログインのフローを区別するには、`context.protocol`を確認します。

```javascript lines theme={null}
function (user, context, callback) {
    if (context.protocol === "redirect-callback") {
        // User was redirected to the /continue endpoint
    } else {
        // User is logging in directly
    }
}
```

## パスワード変更の強制の例

特定の条件下で、ユーザーにパスワード変更を強制する場合、次の動作のルールを作成できます。

1. ユーザーがログインを試み、パスワードを変更する必要がある。
2. クエリ文字列にJWTがあるアプリケーション固有のページにユーザーがリダイレクトされる。このJWTにより、このユーザーのパスワードだけが変更でき、アプリケーションによって**検証されなければならない** ことが保証される。
3. アプリケーションが[Auth0 Management API](/docs/ja-jp/api/v2#!/Users/patch_users_by_id)
4. ユーザーがパスワードを変更したら、アプリケーションは検証済みのデコードされたJWTから`authorize_again`クレームを抽出し、そのURLにユーザーをリダイレクトして、新しいパスワードでサインインできるようにする。

```javascript lines theme={null}
function(user, context, callback) {
   /*
   * Prerequisites:
   * 1. Implement a `mustChangePassword` function
   * 2. Set configuration variables for the following:
   *    - CLIENT_ID
   *    - CLIENT_SECRET
   *    - ISSUER
   */

  const url = require('url@0.10.3');
  const req = context.request;

  function mustChangePassword() {
    // TODO: implement function
    return true;
  }

  if (mustChangePassword()) {
    // User has initiated a login and is forced to change their password
    // Send user's information and query params in a JWT to avoid tampering
    function createToken(clientId, clientSecret, issuer, user) {
      const options = {
        expiresInMinutes: 5,
        audience: clientId,
        issuer: issuer
      };
      return jwt.sign(user, clientSecret, options);
    }

    const token = createToken(
      configuration.CLIENT_ID,
      configuration.CLIENT_SECRET,
      configuration.ISSUER,
      {
        sub: user.user_id,
        email: user.email,
        authorize_again: url.format({
          protocol: 'https',
          hostname: auth0.com,
          pathname: '/authorize',
          query: req.query
        })
      }
    );

    context.redirect = {
      url: `https://example.com/change-pw?token=${token}`
    };
  }

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

## データの保管場所

Auth0のプロファイルに保管するデータは多すぎないようにします。このデータは認証および認可の目的で使用されるものです。Auth0のメタデータと検索機能は、市場調査や高い検索・更新の頻度が必要なものを想定して設計されていません。Auth0をそのような目的で使用すると、ほぼ確実にシステムの拡張性や性能に問題が生じます。データを外部システムに保管して、Auth0にポインター（ユーザーID）を保管した方が、バックエンドシステムが必要に応じてデータを取得できます。従うべきルールはシンプルです。トークンに追加したり決定したりするためにルールで使用する予定のアイテムだけを保管します。

## セキュリティに関する考慮事項

情報をフロントチャネルでやり取りすると、悪意のある行為者の攻撃対象になる領域を広げることになります。これは必ず、ルールで対処しなければならない場合（`UnauthorizedError`での認可試行の拒否など）にのみ行う必要があります。

ただし、直接Auth0に通信を返し、アクセスを制限する指示を与える必要がある場合（CAPTCHA認証やカスタムMFAを実装する場合など）には、その操作の要件が実行されたことをAuth0に安全に伝える方法を確保する必要があります。同様に、リダイレクト先のアプリケーションに情報を渡す必要がある場合、転送された情報が改ざんされていないことを保証する安全な方法を確保する必要があります。

### アプリが確実に同じユーザーにログインするようにする

アプリケーションは、ユーザーをリダイレクトしてAuth0テナントに戻します。そのため、そのユーザーに関連するあらゆるデータを、アプリケーションに戻されるIDトークンを介して収集することができます。ただし、その間にいかなる改ざんも行われていないことを保証するため、リダイレクト元と同じユーザーにアプリケーションが確実にログインする必要があります。そのため、要求と一緒にトークンを送信する必要があるかもしれません。

アプリに送信されるトークンには、次の要件があります。

| トークン要素      | 説明                                                                                                                                                                                                                                                                                                                  |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `sub`       | ユーザーのAuth0での`user_id`です。                                                                                                                                                                                                                                                                                            |
| `iss`       | ルール自体を特定する識別子です。                                                                                                                                                                                                                                                                                                    |
| `aud`       | リダイレクト先のアプリケーションです。                                                                                                                                                                                                                                                                                                 |
| `jti`       | ランダムに生成された文字列で、確認のためにユーザーオブジェクト内に保管されます（ルールコードでuser.jti = uuid.v4();を設定し、作成したトークンのjtiとして追加します）。 /continueが呼び出されて、ルールが再び実行されるときにも、まだuser.jtiは設定されたままです。これは仕様に沿ったものです。                                                                                                                                                |
| `exp`       | できる限り短くして、トークンが再利用されないようにします。                                                                                                                                                                                                                                                                                       |
| `other`     | 渡す必要のある他のカスタムクレーム情報です。                                                                                                                                                                                                                                                                                              |
| `signature` | アプリケーションが安全にシークレットを保管できる場合には、HS256署名を使用することができます。これは、ソリューションの複雑性を大幅に軽減します。また、返されるトークンにも署名が必要なため、これはソリューションの必須条件でもあります。RS256を使うこともできますが、証明書を作成し、期限が切れると更新する必要があります。ルールに直接情報を返さない場合は、この中間アプリにSPAを使用し、RS256を使うようにすれば、アプリケーションでその情報を保管する必要がなくなります。トークンを検証する手段として、イントロスペクションエンドポイントを使用するか、パブリックなJWKSエンドポイントを使用する必要があります。 |

<Warning>
  このトークンは、ベアラートークンとして**扱わないでください** 。これは、アプリケーションで使用する署名付きの情報です。アプリケーションは、ユーザーを認証するためにAuth0にリダイレクトする必要があります。
</Warning>

### 情報をルールへ戻す

大半のシナリオでは、ルールからアプリケーションに情報を渡します。アプリケーションは、必要なストレージにかかわらず、情報を安全に保管できるはずです。アプリやユーザーメタデータをAuth0で更新することが目的であっても、Management APIを使用できます。ユーザー情報の更新は、ユーザーを`/continue`エンドポイントにリダイレクトで戻す前に更新が完了する限り、達成されます。ルール自体が情報を取得する必要があり、その情報がこの特定のサインインだけに関連する場合にのみ、セッションが情報をルールに戻すようにします。

`/continue`エンドポイントに情報を戻す際、渡されるトークンは次の要件に従う必要があります。

| トークン要素      | 説明                                                                                                                                                              |
| ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `sub`       | ユーザーのAuth0 `user_id`です。                                                                                                                                         |
| `iss`       | リダイレクト先のアプリケーションです。                                                                                                                                             |
| `aud`       | ルール自体を識別する何らかの識別子です。                                                                                                                                            |
| `jti`       | アプリケーションに渡されたトークンに含まれていたのと同じJTIです（注意：user.jtiと一致しなければ失敗します）。                                                                                                    |
| `exp`       | トークンの再利用を防ぐため、できる限り短くします。                                                                                                                                       |
| `other`     | 渡す必要がある他のカスタムクレーム情報です。                                                                                                                                          |
| `signature` | アプリケーションにシークレットを保管する安全な場所がある場合は、HS256での署名を使用できます。これによりソリューションの複雑さが大幅に軽減されます。また、返されるトークンも署名が必要なため、このソリューションでは必須です。RS256も使用できますが、証明書を作成し、期限が切れると証明書を更新しなければなりません。 |

クエリパラメーターとして渡すのではなく、POSTを使用して送信し、`context.request.body.token`（または類似のもの）で取得する必要があります。これは、認証のform-postメソッドに似ています。

`/continue`エンドポイントに情報を戻さないのであれば、有効期間が短く、リプレー攻撃がほぼ不可能な場合を除き、 JTIを拒否リストに登録することをお勧めします。

## 制約と制限

リダイレクトルールは、以下では動作しません。

* [リソース所有者 のエンドポイント](/docs/ja-jp/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)

`context.protocol`を確認することで、上記のケースを検出できます。

* パスワードの交換：`context.protocol === 'oauth2-password'`
* リフレッシュトークンの交換：`context.protocol === 'oauth2-refresh-token'`
* リソースオーナーのログイン：`context.protocol === 'oauth2-resource-owner'`

### セッションタイムアウト

リダイレクトルールのセッションは、**［Login Session Management（ログインセッションの管理）］** 設定でより短いタイムアウトを設定した場合を除き、通常3日間有効です。これらの設定は、[テナントの高度な設定](https://manage.auth0.com/#/tenant/advanced)で確認できます。

### リソース所有者 のエンドポイント

`/oauth/token`をリソース所有者のパスワード付与で直接呼び出す場合、リダイレクトルールを使用することはできません。そもそもユーザーがリダイレクトフローにいないため、ルールでユーザーをリダイレクトすることはできません。context.redirectを設定しようと試みると、ログイン試行は失敗し、interaction\_requiredエラーになります。

### prompt=noneの場合のフロー

`prompt=none`は、ユーザーが入力を求められるシナリオを避けることを目的としているため、あらゆるリダイレクトの結果は`error=interaction_required`になります。

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

`prompt=none`の場合、トークンへのアクセスを阻止し、リダイレクトルールをバイパスするリダイレクトフローは作成できません。これは、最初の実行でルールが失敗してもユーザーの認証セッションが作成されるため、試行が失敗すると、ユーザーが`prompt=none`で再び呼び出してトークンを取得できるからです。

### リフレッシュトークン

リフレッシュトークンの使用には`/oauth/token`へのバックチャネル呼び出しが必要なため、`context.redirect`を設定した場合、これも失敗します。

ログインに関するどのような制約も、適用されたかを安全に検証することは困難です。MFAチャレンジに成功したユーザーなど、セッションに関する情報を集めるのに使用可能なコンテキストでは、恒常的なセッションIDはありません。そのため、`prompt=none`はまったく使用できません。

ルールに`context.redirect` が設定されている場合は常に、`prompt=none`が渡された場合、認可は`error=interaction_required`で失敗します。ところが、ルールが失敗の場合でもユーザーのセッションは作成されるため、ユーザーがすべての`context.redirect`チャレンジを渡したことを信頼できません。そのため、トークンの取得方法として`prompt=none`は使用できません。

この特有なケースには、リフレッシュトークンの排他的な使用をお勧めします。リフレッシュトークンの生成にチャレンジが必要な場合に、ユーザーがチャレンジに成功したことを確認できるからです。

## もっと詳しく

* [ユーザーをリダイレクトする](/docs/ja-jp/authenticate/login/redirect-users-after-login)
* [プログレッシブプロファイリングの仕組みを理解する](/docs/ja-jp/manage-users/user-accounts/user-profiles/progressive-profiling)
* [代替ログアウトでユーザーをリダイレクトする](/docs/ja-jp/authenticate/login/logout/redirect-users-after-logout)
