> ## 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.

> リフレッシュトークンメタデータとセッションメタデータのユースケースについて、実装例を紹介します。

# リフレッシュトークンメタデータとセッションメタデータのユースケース

[リフレッシュトークンメタデータ](/docs/ja-jp/secure/tokens/refresh-tokens/refresh-token-metadata) と [セッションメタデータ](/docs/ja-jp/manage-users/sessions/session-metadata) を併用すると、ユーザーの Auth0 セッションのライフサイクル全体を通じて維持されるデータを作成・保存できます。この記事では、次のユースケースの例を紹介します。

* [永続的なカスタムクレームを作成する](/docs/ja-jp/secure/tokens/refresh-tokens/refresh-token-metadata/use-cases#create-persistent-custom-claims)
* [一意のセッション ID を作成する](/docs/ja-jp/secure/tokens/refresh-tokens/refresh-token-metadata/use-cases#create-a-unique-session-id)
* [テナント識別子を引き継ぐ](/docs/ja-jp/secure/tokens/refresh-tokens/refresh-token-metadata/use-cases#create-a-tenant-identifier)
* [アップストリーム ID プロバイダー (IdP) からの一時的なデータを管理する](/docs/ja-jp/secure/tokens/refresh-tokens/refresh-token-metadata/use-cases#manage-transient-data-from-upstream-identity-providers-idps)
* [セキュリティと不正検知を強化する](/docs/ja-jp/secure/tokens/refresh-tokens/refresh-token-metadata/use-cases#enhance-security-and-fraud-detection)

詳しくは、[A guide to Auth0 Session and Refresh Token Metadata](https://auth0.com/blog/auth0-session-refresh-token-metadata-guide) を参照してください。

<Warning>
  Auth0 のセッションメタデータは安全なデータストアではないため、機密情報の保存には使用しないでください。これには、シークレットや、社会保障番号やクレジットカード番号などの高リスクな個人識別情報 (PII) が含まれます。Auth0 を利用するお客様には、メタデータに保存するデータを慎重に評価し、アイデンティティ/アクセス管理の目的に必要なものだけを保存することを強く推奨します。詳しくは、[Auth0 General Data Protection Regulation Compliance](/docs/ja-jp/secure/data-privacy-and-compliance/gdpr) を参照してください。
</Warning>

<div id="create-persistent-custom-claims">
  ## 永続的なカスタムクレームを作成する
</div>

リフレッシュトークンメタデータとセッションメタデータを組み合わせることで、[ID](/docs/ja-jp/secure/tokens#id-tokens) トークンや [access](/docs/ja-jp/secure/tokens/access-tokens) トークンに含まれる情報を拡張するための、永続的なカスタムクレームを作成できます。

永続的なカスタムクレームを使用すると、次のようなアプリケーション固有のデータにアクセスできます。

* ユーザーロール
* 権限
* テナントID
* リフレッシュトークン交換をまたいで認可やパーソナライズに必要となるその他の属性

[post-login](/docs/ja-jp/customize/actions/explore-triggers/signup-and-login-triggers/login-trigger#login-/-post-login) [Action](/docs/ja-jp/customize/actions) トリガーを設定して永続的なカスタムクレームを作成し、`api.refreshToken.setMetadata()` を使用してそれらをリフレッシュトークンメタデータに割り当てます。

```javascript custom claim Action example expandable theme={null}
/**
 * @param {Event} event - ユーザーと認証トランザクションに関する詳細。
 * @param {PostLoginActionAPI} api - 完了した認証トランザクションを変更するためのインターフェース。
 */
exports.onExecutePostLogin = async (event, api) => {
  let customClaimValue1;
  let customClaimValue2;

  // --- カスタムクレームの計算をシミュレートするヘルパー関数 ---
  // 実際のシナリオでは、ユーザーデータや外部APIなどに基づいて
  // 複雑なロジックを実行します。
  const calculateCustomClaims = (user) => {
    // 計算完了後に返す
    return { claim1: value1, claim2: value2 };
  };

  // --- 初回ログインかリフレッシュトークン交換かを判定する ---
  // event.request.body.grant_type が 'refresh_token' でない場合は、初回のインタラクティブログインと判断されます
  const isRefreshTokenGrant = event.request.body.grant_type === 'refresh_token';

  if (!isRefreshTokenGrant) {
    // --- 初回ログイン（例：パスワード、ソーシャル、MFA-OOB）---
    // カスタムクレームの値を計算する
    const calculatedClaims = calculateCustomClaims(event.user);
    customClaimValue1 = calculatedClaims.claim1;
    customClaimValue2 = calculatedClaims.claim2;

    // 計算した値をリフレッシュトークンメタデータに保存して永続化する
    // リフレッシュトークンが発行される場合はメタデータを追加する
if (event.transaction.requested_scopes.indexOf('offline_access') > -1) {
api.refreshToken.setMetadata('customClaim1', customClaimValue1);
api.refreshToken.setMetadata('customClaim2', customClaimValue2);
}

  } else {
    // --- リフレッシュトークン交換 ---
    // リフレッシュトークンメタデータからカスタムクレームの値を取得する
    customClaimValue1 = event.refresh_token?.metadata?.customClaim1;
    customClaimValue2 = event.refresh_token?.metadata?.customClaim2;

  } 
  // --- 最後に、確定した値をカスタムクレームとしてトークンに追加する ---
  api.idToken.setCustomClaim('custom_claim_1', customClaimValue1);
  api.accessToken.setCustomClaim('custom_claim_1', customClaimValue1);

  api.idToken.setCustomClaim('custom_claim_2', customClaimValue2);
  api.accessToken.setCustomClaim('custom_claim_2', customClaimValue2);
};
```

[リフレッシュトークンの交換](/docs/ja-jp/secure/tokens/refresh-tokens/use-refresh-tokens#use-refresh-tokens)時には、後続の`post-login` Action トリガーで`event.refresh_token.metadata`オブジェクトを使ってこれらのカスタムクレームにアクセスし、`api.idToken.setCustomClaim()`および`api.accessToken.setCustomClaim()`を使って、新たに発行されるリフレッシュトークンに適用できます。

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">
  1 つの`post-login` Actionで、`event.request.body.grant_type`オブジェクトを使ってクレームの保持を管理しながら、異なる`grant_type`のシナリオに対応できます。`event.refresh_token`オブジェクトは、リフレッシュトークンの交換時にのみ読み取り専用で利用できます。
</Callout>

<div id="create-a-unique-session-id">
  ## 一意のセッション ID を作成する
</div>

リフレッシュトークンメタデータとセッションメタデータを組み合わせることで、一意のセッション ID を作成し、[refresh token rotations](docs/secure/tokens/refresh-tokens/refresh-token-rotation) の間も含めて、ユーザーのセッション全体を通して維持される永続的なセッション識別子を実装できます。

一意のセッション ID を使用すると、次のことができます。

* デバッグや監査のために、ユーザーのセッションを正確に記録する。
* アプリケーションが内部セッションの状態を追跡するための仕組みを提供する。
* [API](/docs/ja-jp/get-started/apis#apis) で、きめ細かなログ記録、レート制限、コンテキストに応じた認可の判断を可能にする。
* 複数のトークンライフサイクルにまたがって、一貫した UX を実現する。

[post-login](/docs/ja-jp/customize/actions/explore-triggers/signup-and-login-triggers/login-trigger#login-/-post-login) Action トリガーを設定して一意のセッション ID を作成し、`api.session.setMetadata()` オブジェクトと `api.refreshToken.setMetadata()` オブジェクトを使用して、ユーザーのセッションに割り当てます。

`api.idToken.setCustomClaim()` オブジェクトと `api.accessToken.setCustomClaim()` オブジェクトを使用して、一意のセッション ID をカスタムクレームとして ID トークンとアクセストークンに追加します。

```javascript unique session ID Action example expandable theme={null}
/**
 * @param {Event} event - ユーザーと認証トランザクションに関する詳細。
 * @param {PostLoginActionAPI} api - 完了した認証トランザクションを変更するためのインターフェース。
 */
exports.onExecutePostLogin = async (event, api) => {
  let sessionId;

  // 1) 'ses_id' というセッションメタデータキーがすでに存在するか確認する。
  if (event.session && event.session.metadata && event.session.metadata.ses_id) {
    sessionId = event.session.metadata.ses_id;
  }
  // セッションメタデータに見つからない場合は、リフレッシュトークンメタデータに存在するか確認する。
  // これは、実際のセッションが存在しない ROPG フローに特に関係する。
  else if (event.refresh_token && event.refresh_token.metadata && event.refresh_token.metadata.ses_id) {
    sessionId = event.refreshToken.metadata.ses_id;
  }

  // 'ses_id' が存在しない場合は、新たに生成する 
  if (!sessionId) {
    sessionId = generateSesId(); // UUID を生成する独自のヘルパー関数

    // 新たに生成した 'ses_id' をセッションメタデータに保存する
    // セッションが実際に発行されている場合、またはイベントに含まれている場合にのみ実行する。 
    if (event.session) {
      api.session.setMetadata('ses_id', sessionId);
    }

    // 'ses_id' をリフレッシュトークンメタデータに保存する。
    // リフレッシュトークンが実際に発行されている場合、またはイベントに含まれている場合にのみ実行する。
    if (event.refresh_token) {
      api.refreshToken.setMetadata('ses_id', sessionId);
    }
  } else {
    // リフレッシュトークンメタデータに ses_id が含まれていることを確認する。
    // 値が欠落している場合や別の場所で更新された場合に備えるため。
    // ユーザーが最初に offline_access をリクエストせず、後から追加した場合に発生する可能性がある。
    if (event.refresh_token && event.refresh_token.metadata && !event.refresh_token.metadata.ses_id) {
        api.refreshToken.setMetadata('ses_id', sessionId);
    }
  }


  // 2) この 'ses_id' をカスタムクレームとして ID トークンとアクセストークンの両方に追加する。
  api.idToken.setCustomClaim('ses_id', sessionId);
  api.accessToken.setCustomClaim('ses_id', sessionId);
};
```

リフレッシュトークン交換時には、後続の post-login Action トリガーで `event.refresh_token.metadata` オブジェクトを通じてこれらのカスタムクレームにアクセスし、`api.idToken.setCustomClaim()` および `api.accessToken.setCustomClaim()` を使用して、新たに発行されるリフレッシュトークンにそれらを適用できます。

<div id="create-a-tenant-identifier">
  ## テナント識別子を作成する
</div>

リフレッシュトークンメタデータとセッションメタデータを組み合わせることで、永続的なテナント識別子を作成できます。これにより、1 つのアプリケーションインスタンスで複数の顧客組織に対応するマルチテナントアプリケーションにおいて、ユーザーのセッションの全期間を通じてテナント識別子を保持できます。

永続的なテナント識別子を使用すると、次のことが可能になります。

* 動的なアクセス制御を追加し、アプリケーションや API でテナント固有の権限を簡単に適用する
* ユーザーの現在のテナントコンテキストに応じたコンテンツや機能を提供し、最適なユーザー体験を実現する
* Auth0 内でテナントの識別と伝播を一元化し、マルチテナントロジックを簡素化する
* すべてのトークンで一貫したテナントコンテキストを確保することで、テナント間での意図しないデータ露出を防ぎ、セキュリティを強化する
* API 呼び出しやトークン更新のたびにテナントコンテキストを判定するためのデータベースクエリの繰り返しや複雑なロジックを減らし、スケーラビリティを向上させる

[post-login](/docs/ja-jp/customize/actions/explore-triggers/signup-and-login-triggers/login-trigger#login-/-post-login) Action トリガーを設定して、認証リクエスト時に渡される `ext-tenantId` の値をアプリケーションに問い合わせてユーザーのアクティブなテナントを特定するか、地理的位置情報からテナントを推定するか、またはユーザーに使用するテナントを選択してもらいます。

テナントが特定されたら、`api.session.setMetadata()` と `api.refreshToken.setMetadata()` を使用してテナント識別子の値をユーザーのセッションに割り当て、`api.idToken.setCustomClaim()` と `api.accessToken.setCustomClaim()` を使用して、その値を ID トークンおよびアクセストークンのカスタムクレームとして追加します。

```javascript tenant identifier Action example expandable theme={null}
/** 
 * @param {Event} event - ユーザーと認証トランザクションに関する詳細情報。
 * @param {PostLoginActionAPI} api - 完了した認証トランザクションを変更するためのインターフェース。
 */
exports.onExecutePostLogin = async (event, api) => {
  let tenantId;

  // 1) 'tenant_id' というセッションメタデータキーが既に存在するかどうかを確認する。
  if (event.session && event.session.metadata && event.session.metadata.tenant_id) {
    tenantId = event.session.metadata.tenant_id;
  }
  // セッションメタデータに見つからない場合は、リフレッシュトークンメタデータを確認する。
  // これは実際のセッションが存在しない ROPG フローに特に関係する。
  else if (event.refresh_token && event.refresh_token.metadata && event.refresh_token.metadata.tenant_id) {
    tenantId = event.refreshToken.metadata.tenant_id;
  }

  // 'tenant_id' がまだ不明な場合は、ここで特定する 
  if (!tenantId) {
    // tenant_id は ext- パラメーターとして渡されたものと想定する
    tenantId = event.request.query['ext-tenantId'];

    // イベントのジオロケーションや Form から取得することも可能。
    // Form を使用する場合は、ここで Form を開き、
    // 残りの処理を
    // onContinuePostLogin 関数内で実行する
  
    // 新たに取得した 'tenant_id' をセッションメタデータに保存する
    // セッションが実際に発行されている場合、またはイベントに存在する場合のみ実行する。 
    if (event.session) {
      api.session.setMetadata('tenant_id', tenantId);
    }

    // 'tenant_id' をリフレッシュトークンメタデータに保存する。
    // リフレッシュトークンが実際に発行されている場合、またはイベントに含まれている場合のみ実行する。
    if (event.refresh_token) {
      api.refreshToken.setMetadata('tenant_id', tenantId);
    }
  } else {
    // リフレッシュトークンのメタデータに tenant_id が含まれていることを確認する。
    // tenant_id が欠落していたり、別の場所で更新されている場合に備えるため。
    // ユーザーが最初に offline_access をリクエストせず、後から追加した場合などに発生する可能性がある。
    if (event.refresh_token && event.refresh_token.metadata && !event.refresh_token.metadata.tenant_id) {
        api.refreshToken.setMetadata('tenant_id', tenantId);
    }
  }


  // 2) この 'tenant_id' をカスタムクレームとして ID Token とアクセストークンの両方に追加する。
  api.idToken.setCustomClaim('tenant_id', tenantId);
  api.accessToken.setCustomClaim('tenant_id', tenantId);
};
```

リフレッシュトークン交換時には、後続の `post-login` Action で `event.refresh_token.metadata` オブジェクトを使用してこれらのカスタムクレームにアクセスし、`api.idToken.setCustomClaim()` および `api.accessToken.setCustomClaim()` を使って、新たに発行されるリフレッシュトークンに適用できます。

<div id="manage-transient-data-from-upstream-identity-providers-idps">
  ## アップストリーム ID プロバイダー (IdP) からの一時データを管理する
</div>

リフレッシュトークンメタデータとセッションメタデータを併用すると、ユーザーの Auth0 プロファイルに永続保存することなく、ユーザーのセッション全体を通してアップストリーム ID プロバイダー (IdP) からの一時的なデータやコンテキストデータを管理できます。

一時データを使用すると、次のことが可能です。

* 一時データやセッション固有のデータが保存されないようにして、クリーンなユーザープロファイルを維持する
* 永続的なユーザープロファイルにスキーマ変更やデータ肥大化を強いることなく、さまざまなIDプロバイダーの多様なデータ要件に対応し、柔軟性を高める
* 一時データを必要な期間だけ保存することで、データプライバシーおよび保持ポリシーへの準拠を容易にし、コンプライアンスを向上させる
* Auth0 Actions とメタデータがデータのライフサイクルを管理するため、一時的なIDプロバイダーデータの処理を簡素化し、開発負荷を軽減する

[post-login](/docs/ja-jp/customize/actions/explore-triggers/signup-and-login-triggers/login-trigger#login-/-post-login) Action トリガーを設定し、`event.request`、`event.user`、`event.context` オブジェクトに含まれるユーザープロファイルデータを識別します。

どのデータが一時データまたはコンテキストデータに当たるかを判断し、`api.session.setMetadata()` と `api.refreshToken.setMetadata()` オブジェクトを使用してそれをユーザーのセッションに割り当てます。また、`api.idToken.setCustomClaim()` と `api.accessToken.setCustomClaim()` オブジェクトを使用して、その一時データを ID トークンとアクセストークンにカスタムクレームとして追加します。

```javascript transient data Action example expandable theme={null}
/**
 * @param {Event} event - ユーザーと認証トランザクションに関する詳細情報。
 * @param {PostLoginActionAPI} api - 完了した認証トランザクションを変更するインターフェース。
 */
exports.onExecutePostLogin = async (event, api) => {
  let deviceIdentifier;
  let groups;

  // 例: リクエストヘッダーまたはコンテキストからデバイス情報を抽出する
  // これはあくまで例示であり、実際のデバイスフィンガープリンティングはより複雑になる場合があります
  if (event.request.user_agent) {
    deviceIdentifier = event.request.user_agent;
  } else {
    deviceIdentifier = 'unknown';
  }

  // 例: 上流の接続のコンテキストからIDP情報を抽出する
  // この処理は上流のIDPとその情報の渡し方に大きく依存します。
  // SAML/OIDC接続からのカスタムクレームまたはコンテキスト変数（例: "groups"）を想定
  if (event.user.groups) {
    groups = event.user.groups;
  } else {
    groups = [];
  }

  // 一時データをセッションメタデータに保存する
  api.session.setMetadata('deviceIdentifier', deviceIdentifier);
  api.session.setMetadata('groups', groups);

  // リフレッシュをまたいでデータを永続化するために、一時データをリフレッシュトークンメタデータに保存する
  if (event.refreshToken) {
    api.refreshToken.setMetadata('deviceIdentifier', deviceIdentifier);
    api.refreshToken.setMetadata('groups', groups);
  }

  // 必要に応じて、APIが必要とする場合はアクセストークンにクレームとして追加する
  // アプリケーション固有のクレームにはカスタム名前空間を使用することが推奨されます。
  api.accessToken.setCustomClaim('https://myapp.example.com/device_id', deviceIdentifier);
  api.accessToken.setCustomClaim('https://myapp.example.com/groups', groups);

  // 例: 上流のIDPがこの認証イベントに「保証レベル」を提供する場合
  if (event.transaction && event.transaction.acr_values) { // acr: 認証コンテキストクラスリファレンス
      api.session.setMetadata('authLevel', event.transaction.acr_values);
      if (event.refreshToken) {
        api.refreshToken.setMetadata('authLevel', event.transaction.acr_values);
      }
      api.accessToken.setCustomClaim('https://myapp.example.com/auth_level', event.transaction.acr_values);
  }
};
```

リフレッシュトークンの交換時には、後続の`post-login` Actionトリガーで`event.refresh_token.metadata`オブジェクトを通じてこれらのカスタムクレームにアクセスし、`api.accessToken.setCustomClaim()`オブジェクトを使用して、新たに発行されるリフレッシュトークンにそれらを適用できます.

<div id="enhance-security-and-fraud-detection">
  ## セキュリティ強化と不正検知
</div>

リフレッシュトークンメタデータとセッションメタデータを組み合わせることで、リフレッシュトークンのローテーションや[サイレント認証](/docs/ja-jp/authenticate/login/configure-silent-authentication)のリクエストを含め、ユーザーのセッション全体を通じてコンテキスト情報を追跡・比較できるようになり、適応型セキュリティを実装できます。

適応型セキュリティを実装すると、次のことが可能になります。

* ユーザーのコンテキストデータにおける不審な変化を自動的に検出して対応することで、脅威を早期に検知し、セッションハイジャックや不正アクセスのリスクを低減できます。
* 正当なユーザーに対する負担を減らし、実際に異常が検出された場合にのみMFAや追加の確認を求めることで、一律にMFAを要求する場合と比べてユーザー体験を向上できます。

[post-login](/docs/ja-jp/customize/actions/explore-triggers/signup-and-login-triggers/login-trigger#login-/-post-login) Action トリガーを設定して、デバイスフィンガープリント、地理的位置情報、ネットワーク属性、行動属性などのコンテキストに関するユーザーデータを特定します。比較用のコンテキストデータは、`api.session.setMetadata()`オブジェクトを使用してユーザーのセッションに保存します。

```javascript security detection Action example expandable theme={null}
/**
 * @param {Event} event - ユーザーと認証トランザクションに関する詳細情報。
 * @param {PostLoginActionAPI} api - 完了した認証トランザクションを変更するためのインターフェース。
 */
exports.onExecutePostLogin = async (event, api) => {
  // --- 現在のコンテキストデータを取得 ---
  // Auth0が提供するja3/ja4フィンガープリントを使用する
  const {ja3, ja4} = event.security_context;
  // ja3/ja4がメタデータに未登録の場合は追加する
  // （初回ログイン時はメタデータが設定されていない）
  if (event.session && !event.session.metadata) {
    api.session.setMetadata('ja3', ja3);
    api.session.setMetadata('ja4', ja4);
  } else {
    // 保存済みフィンガープリントと受信フィンガープリントを比較する 
    if(ja3 != event.session?.metadata?.ja3 || ja4 != event.session?.metadata?.ja4) {
      // フィンガープリントが一致しない場合、MFAチャレンジを要求する
      api.authentication.challengeWith(
        { type: 'otp'}, 
        { additionalFactors: [
          { type: 'push-notification'}, { type: 'phone' }
        ]}
      );
    }    
  }
};
```

リフレッシュトークン交換時またはサイレント認証時には、後続の`post-login Action` トリガーでリスク評価と適応型の対応を適用できます。

<div id="access-metadata-with-the-management-api">
  ## Management API を使用してメタデータにアクセスする
</div>

Auth0 Management API の `GET` [/api/v2/refresh-tokens/\{id}](/docs/ja-jp/api/management/v2/refresh-tokens/get-refresh-token) および [/api/v2/sessions/\{id}](/docs/ja-jp/api/management/v2/sessions/get-session) エンドポイントを使用すると、リフレッシュトークンまたはセッションのメタデータに保存されたデータを取得できます。

レスポンスには、保存されたデータを含む `metadata` フィールドが含まれます。

```json theme={null}
{
  "id": "object_id",
  "metadata": {
    "deviceIdentifier": "deviceIdentifier"
  }
}
```

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

* [リフレッシュトークン](/docs/ja-jp/secure/tokens/refresh-tokens): リフレッシュトークンについて説明します。
* [セッション](/docs/ja-jp/manage-users/sessions): セッションについて説明します。
* [Actions Event objects](/docs/ja-jp/customize/actions/explore-triggers/signup-and-login-triggers/login-trigger/post-login-event-object): `post-login` イベントオブジェクトとそのプロパティについて説明します。
* [Actions API object](/docs/ja-jp/customize/actions/explore-triggers/signup-and-login-triggers/login-trigger/post-login-api-object): `post-login` API オブジェクトとそのメソッドについて説明します。
