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

> Auth0 で Demonstrating Proof-of-Possession（DPoP）を使用して、アクセストークンに送信者制約を適用する方法を説明します。

# Demonstrating Proof-of-Possession (DPoP)

Demonstrating Proof-of-Possession (DPoP) は、アプリケーション層で非対称暗号方式と <Tooltip tip="アクセストークン: API へのアクセスに使用される、不透明な文字列または JWT 形式の認可資格情報。" cta="用語集を見る" href="/ja/docs/glossary?term=JSON+Web+Tokens">JSON Web Token</Tooltip> (JWT) を使用して、<Tooltip tip="アクセストークン: API へのアクセスに使用される、不透明な文字列または JWT 形式の認可資格情報。" cta="用語集を見る" href="/ja/docs/glossary?term=access+tokens">アクセストークン</Tooltip>をバインドし、[送信者制約を適用](/ja/docs/secure/sender-constraining)するための [OAuth 2.0 のフレームワーク拡張](https://datatracker.ietf.org/doc/draft-ietf-oauth-dpop/) です。DPoP により、アクセストークンを要求し、その秘密鍵を保持しているクライアントアプリケーションだけが、そのトークンを使用できるようになります。これにより、盗まれたトークンの悪用を防止できます。

DPoP では、公開鍵と秘密鍵のペアを使用して、署名付き JSON Web Token (JWT) として DPoP Proof を作成します。DPoP Proof には、次の内容が含まれます。

* クライアントの公開鍵 (`jwk`) 。
* メソッド (`htm`) と URI (`htu`) を含む、アクセストークンリクエストを参照するペイロード。
* クライアントの秘密鍵を使用して生成された署名。
* リプレイ防止のための一意の ID (`jti`) 。
* すべての API リクエストに対する、アクセストークンの base64url エンコード済み SHA-256 ハッシュ (`ath`) 。
* 任意: <Tooltip tip="Public Client: 認証情報を安全に保持できないクライアント（アプリケーション）。例として、ネイティブのデスクトップアプリケーションやモバイルアプリケーション、JavaScript ベースのクライアントサイド Web アプリケーション（single-page app（SPA）など）があります。" cta="用語集を見る" href="/ja/docs/glossary?term=public+clients">パブリッククライアント</Tooltip> の場合、クライアントアプリケーションが DPoP Proof JWT を最近生成したことを保証するための `nonce` claim。

クライアントアプリケーションは、アクセストークンリクエストで DPoP Proof JWT を Auth0 の <Tooltip tip="認可サーバー: ユーザーのアクセス境界の定義に関与する集中管理型サーバーです。たとえば、認可サーバーはユーザーが利用できるデータ、タスク、機能を制御できます。" cta="用語集を見る" href="/ja/docs/glossary?term=Authorization+Server">認可サーバー</Tooltip> に送信します。Auth0 の認可サーバーは DPoP Proof JWT を検証した後、発行するアクセストークンをクライアントの公開鍵にバインドします。

<div id="common-use-cases">
  ## 一般的なユースケース
</div>

代表的な DPoP のユースケースをいくつか紹介します。

* **シングルページアプリケーション (SPA) とモバイルアプリケーション：** パブリッククライアントである SPA やモバイルアプリケーションには、バックエンドサーバーのように <Tooltip tip="クライアントシークレット: クライアント（アプリケーション）が認可サーバーで認証するために使用するシークレットです。これはクライアントと認可サーバーだけが知るべきものであり、推測できない十分なランダム性が必要です。" cta="用語集を見る" href="/ja/docs/glossary?term=client+secrets">クライアントシークレット</Tooltip>を安全に保存できる、信頼された機密環境がありません。そのため、トークンの窃取に対して脆弱です。DPoP は、アクセストークンをクライアントアプリケーションの公開鍵にバインドして DPoP Proof JWT を生成することで、このセキュリティ上の脆弱性に対処します。クライアントアプリケーションは秘密鍵で DPoP Proof JWT に署名し、認可リクエストに含めて送信します。Auth0 の認可サーバーは DPoP Proof JWT を検証し、有効であれば発行されたアクセストークンをクライアントの公開鍵にバインドします。
* **サードパーティ API との統合：** クライアントアプリケーションと統合された AI エージェントが、DPoP Proof JWT を使用してユーザーに代わってサードパーティ API を呼び出す場合、<Tooltip tip="リソースサーバー: 保護されたリソースをホストするサーバーです。リソースサーバーは保護されたリソースへのリクエストを受け付け、応答します。" cta="用語集を見る" href="/ja/docs/glossary?term=resource+server">リソースサーバー</Tooltip>は、そのリクエストが認可されていない第三者ではなく AI エージェントから送信されたものであることを、暗号学的に検証できます。

<div id="supported-application-grant-types">
  ## サポートされているアプリケーションのグラントタイプ
</div>

Auth0 は、DPoP の送信者制約で次の [アプリケーションのグラントタイプ](/ja/docs/get-started/applications/application-grant-types) をサポートしています。

| グラントタイプ                                               | 説明                                              |
| ----------------------------------------------------- | ----------------------------------------------- |
| `authorization_code`                                  | 認可コードグラント                                       |
| `client_credentials`                                  | クライアントクレデンシャルグラント                               |
| `password`                                            | リソースオーナーパスワードグラント                               |
| `refresh_token`                                       | リフレッシュトークングラント                                  |
| `urn:ietf:params:oauth:grant-type:device_code`        | デバイス認可グラント                                      |
| `http://auth0.com/oauth/grant-type/password-realm`    | 特定のレルムを指定できる、リソースオーナーパスワードグラントに類似した拡張グラントを使用します |
| `http://auth0.com/oauth/grant-type/passwordless/otp`  | パスワードレス グラントリクエスト                               |
| `http://auth0.com/oauth/grant-type/mfa-oob`           | 多要素認証 OOB グラントリクエスト                             |
| `http://auth0.com/oauth/grant-type/mfa-otp`           | 多要素認証 OTP グラントリクエスト                             |
| `http://auth0.com/oauth/grant-type/mfa-recovery-code` | 多要素認証のリカバリーコード グラントリクエスト                        |
| `urn:ietf:params:oauth:grant-type:token-exchange`     | Custom Token Exchange グラントリクエスト                 |
| `urn:okta:params:oauth:grant-type:webauthn`           | WebAuthn グラントリクエスト                              |

<div id="how-it-works">
  ## 仕組み
</div>

次のシーケンス図は、Auth0 DPoPフローの概要を示しています。

<Frame>
  <img src="https://mintcdn.com/translations/mMSz-RNYLuOm2GmQ/docs/images/cdy7uua7fh8z/XoEV4y12QtnGwBPCiFbep/6744ab830ab2119664463f8c52fe6b02/Screenshot_2025-07-28_at_11.15.42_AM.png?fit=max&auto=format&n=mMSz-RNYLuOm2GmQ&q=85&s=c75e773654d080a4fc99cf1a6b0e0ebe" alt="" width="1256" height="600" data-path="docs/images/cdy7uua7fh8z/XoEV4y12QtnGwBPCiFbep/6744ab830ab2119664463f8c52fe6b02/Screenshot_2025-07-28_at_11.15.42_AM.png" />
</Frame>

1. Auth0 認可サーバーにアクセストークンをリクエストするとき、クライアントアプリケーションは一意の暗号学的キーペアを生成し、公開鍵を使って秘密鍵を保有していることを証明します。
2. クライアントアプリケーションは DPoP Proof JWT を生成し、それを Auth0 認可サーバーの /token エンドポイントに送信します。
3. Auth0 認可サーバーは DPoP Proof JWT を検証し、有効であればアクセストークンを発行して、クライアントの公開鍵にバインドします。
4. Customer API を呼び出す前に、クライアントアプリケーションは新しい DPoP Proof JWT を生成し、トークンに関連付けられた秘密鍵を保有していることを証明します。クライアントアプリケーションは、DPoP Proof JWT と sender-constrained アクセストークンをリソースサーバーに送信します。
5. リソースサーバーは DPoP Proof JWT を検証し、トークンの正当な所有者、つまり元のクライアントアプリケーションだけが、それを使って保護されたリソースに正常にアクセスできるようにします。リフレッシュトークンからアクセストークンをリクエストするには、クライアントアプリケーションは新しい DPoP Proof JWT を生成し、リフレッシュトークンがクライアントの公開鍵にバインドされていることを保証します。

<div id="sender-constrain-tokens-using-dpop-in-auth0">
  ## Auth0 で DPoP を使用してトークンに送信者制約を適用する
</div>

次の図は、Auth0 で DPoP を使用してトークンに送信者制約を適用するエンドツーエンドのフローを示しています。

<Frame>
  <img src="https://mintcdn.com/translations/c0RQ9V0YAcT0-8l5/docs/images/cdy7uua7fh8z/7sonusMpvBMP0fDS6OkXSA/7cd0d50ffc44167f52f7e29d7f723d4a/Screenshot_2025-07-28_at_11.17.43_AM.png?fit=max&auto=format&n=c0RQ9V0YAcT0-8l5&q=85&s=5a29d50e0213083c972c089629ca9b2f" alt="" width="1272" height="806" data-path="docs/images/cdy7uua7fh8z/7sonusMpvBMP0fDS6OkXSA/7cd0d50ffc44167f52f7e29d7f723d4a/Screenshot_2025-07-28_at_11.17.43_AM.png" />
</Frame>

以下のセクションでは、実装用のコードサンプルとともに、Auth0 での DPoP フローを手順に沿って説明します。

* [前提条件](#prerequisites)
* [ステップ 1: クライアントアプリケーションが DPoP キーペアを生成する](#step-1-client-application-generates-a-dpop-key-pair)
* [ステップ 2: クライアントアプリケーションが DPoP Proof JWT を作成する](#step-2-client-application-creates-a-dpop-proof-jwt)
* [ステップ 3: クライアントアプリケーションが DPoP にバインドされたトークンを要求する](#step-3-client-application-requests-a-dpop-bound-token)
* [ステップ 4: Auth0 認可サーバーが DPoP Proof JWT を検証する](#step-4-auth0-authorization-server-validates-the-dpop-proof-jwt)
* [ステップ 5: クライアントアプリケーションが DPoP にバインドされたトークンと DPoP Proof JWT を使用して API を呼び出す](#step-5-client-application-calls-api-with-the-dpop-bound-token-and-dpop-proof-jwt)
* [ステップ 6: DPoP を使用したトークンのリフレッシュを処理する](#step-6-handle-token-refresh-with-dpop)

<div id="prerequisites">
  ## 前提条件
</div>

開始する前に、次のことを確認してください。

* クライアントアプリケーションとリソースサーバーに対して、[送信者制約を設定](/ja/docs/secure/sender-constraining/configure-sender-constraining)していること。

<div id="step-1-client-application-generates-a-dpop-key-pair">
  ## ステップ 1: クライアントアプリケーションが DPoP キーペアを生成する
</div>

DPoP では、クライアントアプリケーションが非対称暗号のキーペアを生成する必要があります。Auth0 は、ES256 キーで使用されるような楕円曲線の利用をサポートしています。このキーペアはクライアントアプリケーションごとに固有であり、たとえばハードウェアベースのキーストアに安全に保管する必要があります。

クライアントアプリケーションは秘密鍵を安全に保持しつつ、[ステップ 2](#step-2-client-application-creates-a-dpop-proof-jwt) で「所持の証明」として機能する DPoP Proof JSON Web Token (JWT) に公開鍵を含めます。

<div id="step-2-client-application-creates-a-dpop-proof-jwt">
  ## ステップ 2: クライアントアプリケーションが DPoP Proof JWT を作成する
</div>

Auth0 認可サーバーの `/token` エンドポイントに DPoP にバインドされたアクセストークンをリクエストする前に、クライアントアプリケーションは DPoP Proof JWT を作成する必要があります。DPoP Proof JWT は、クライアントの秘密鍵で署名された JSON Web Token (JWT) であり、「所持証明」として機能します。

DPoP Proof JWT は、JWT ヘッダーと、トークンリクエストに関連付けられた[クレーム](/ja/docs/secure/tokens/json-web-tokens/json-web-token-claims)を含むペイロードで構成されます:

<div id="jwt-header-claims">
  ### JWT ヘッダークレーム
</div>

| DPoP Proof JWT クレーム | 説明                                   |
| ------------------- | ------------------------------------ |
| `typ`               | `dpop+jwt` に設定します。                   |
| `alg`               | `RS256` や `ES256` などの非対称署名アルゴリズムです。  |
| `jwk`               | クライアントの公開鍵を表す JSON Web Key (JWK) です。 |

<div id="jwt-payload-claims">
  ### JWT ペイロードのクレーム
</div>

| DPoP Proof JWT クレーム | 説明                                                                                                                                                           |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `jti`               | リプレイ攻撃を防ぐための JWT の一意の識別子です。                                                                                                                                  |
| `htm`               | DPoP Proof の対象となるリクエストの HTTP メソッドです。たとえば、トークンリクエストでは `POST`、API 呼び出しでは `GET` です。                                                                             |
| `htu`               | DPoP Proof JWT の対象となるリクエストの HTTP URI です。フラグメントとクエリパラメーターは含まれません。たとえば、`https://api.example.com/data?param=1#section1` は `https://api.example.com/data` になります。 |
| `iat`               | JWT の作成時刻を表すタイムスタンプです。                                                                                                                                       |
| `ath`               | アクセストークンを使用する API 呼び出しでは、アクセストークンを base64url エンコードした SHA-256 ハッシュです。                                                                                         |
| `nonce`             | `nonce` を必要とするパブリッククライアントでは、サーバーから提供される `nonce` 値です。                                                                                                         |

クライアントアプリケーションで DPoP Proof JWT を作成したら、[ステップ 1](#step-1-client-application-generates-a-dpop-key-pair) で生成した秘密鍵を使って DPoP Proof JWT に署名します。

次のコードサンプルは、クライアントアプリケーションで DPoP Proof JWT を作成して署名する方法を示しています。

```jsx lines theme={null}
import { generateKeyPairSync, randomBytes } from 'node:crypto';
import jwt from 'jsonwebtoken';

// DPoP キーペアを生成する
const keyPair = generateKeyPairSync('ec', {
  namedCurve: 'P-256',
});

// トークンリクエスト用の DPoP Proof JWT を構築する
const jti = randomBytes(16).toString('base64url');
const jwk = keyPair.publicKey.export({ format: 'jwk' });
const dpopHeader = jwt.sign({
    jti,
    htm: 'POST',
    htu: 'https://[TENANT]/oauth/token',
    iat: Date.now() / 1000,
  },
  keyPair.privateKey,
  {
    algorithm: 'ES256',
    header: {
      typ: 'dpop+jwt',
      jwk,
    },
  });
```

<div id="step-3-client-application-requests-a-dpop-bound-token">
  ## ステップ 3: クライアントアプリケーションが DPoP にバインドされたトークンをリクエストする
</div>

クライアントアプリケーションが Auth0 の認可サーバーの `/token` エンドポイントにアクセストークンをリクエストする際、HTTP リクエストヘッダーに DPoP Proof JWT を含めます:

```http lines theme={null}
DPoP: {DPoP_proof_JWT_value}
```

以下は、DPoP Proof JWT を設定した DPoP HTTP ヘッダーを含むアクセストークンリクエストの例です。

```http lines theme={null}
POST /oauth/token HTTP/1.1
Host: auth.example.com
Content-Type: application/x-www-form-urlencoded
DPoP: {DPoP Proof JWT}
Authorization: Basic Y2xpZW50MTIzOm15c2VjcmV0
Cache-Control: no-cache
grant_type=client_credentials&client_id=client123
```

クライアントアプリケーションで DPoP にバインドされたアクセストークンをリクエストする処理を実装するには、次のコードサンプルを使用します。このコードサンプルでは、以下を行います。

1. 署名済みの DPoP Proof JWT を使用して、DPoP HTTP ヘッダーを設定します。
2. 署名済みの DPoP Proof JWT を含む DPoP HTTP ヘッダーを、`/token` エンドポイントへのアクセストークンリクエストとともに送信します。
3. Auth0 認可サーバーからのレスポンスを処理します。

```javascript lines theme={null}
// /oauth/token エンドポイントにリクエストを送信する
// [...] を実際の grant_type、client_id、テナント URL に置き換えてください
const response = await fetch('https://[TENANT]/oauth/token', {
    method: 'POST',
    body: new URLSearchParams({
      grant_type: '...',
      client_id: '...',
      // その他のボディパラメーターをここに記述
    }),
    headers: {
      "Content-Type": "application/x-www-form-urlencoded",
      // DPoP ヘッダーを追加する
      dpop: dpopHeader
    }
  });

// Auth0 認可サーバーからのレスポンスを処理する
const result = await response.json();
console.log('Initial token request result:', result);
```

<div id="public-clients">
  ### Public clients
</div>

シングルページアプリケーション (SPA) やモバイルアプリなどのパブリッククライアントが DPoP にバインドされたアクセストークンを要求する場合、クライアントシークレットやその他のクライアント認証パラメーターは使用できません。この場合、[RFC 9449](https://datatracker.ietf.org/doc/html/rfc9449#section-8) に従い、Auth0 では、クライアントアプリケーションが直近に DPoP Proof JWT を生成したことを確認するため、DPoP HTTP ヘッダーに <Tooltip tip="Nonce: リプレイ攻撃を検出して防止するために、認証プロトコルで一度だけ発行される任意の値。" cta="用語集を表示" href="/ja/docs/glossary?term=nonce">nonce</Tooltip> 値を含める必要があります。これは想定どおりの動作です。これにより、認可サーバーは DPoP proof が最新であることを確認し、その proof を使用できる時間枠を制限できます。

パブリッククライアントが `/token` リクエストを行い、DPoP HTTP ヘッダーに `nonce` 値を含めない場合、Auth0 は `HTTP 400` コードと、次のようなエラーメッセージを返します。

```js lines theme={null}
{
  error: 'use_dpop_nonce',
  error_description: '認証サーバーはDPoP証明にnonceを要求します'
}
```

Auth0 は、レスポンスヘッダーに `DPoP-Nonce` ヘッダーを含めます。これは、[DPoP specification](https://datatracker.ietf.org/doc/html/rfc9449) で定義されている標準的な"チャレンジレスポンス"フローに従うものです。`DPoP-Nonce` ヘッダーの値を使用して DPoP proof を再生成し ([Step 2](#step-2-client-application-creates-a-dpop-proof-jwt) と同様) 、その値を持つ `nonce` claim を含めたうえで、リクエストを `/token` エンドポイントに再送信する必要があります。

次のコードサンプルは、パブリッククライアントから `nonce` claim を含む `/token` リクエストを送信し、その後再試行するまでの一連のフローを示しています。

```jsx lines expandable theme={null}
import { generateKeyPairSync, randomBytes } from 'node:crypto';
import jwt from 'jsonwebtoken';

// DPoP キーペアを生成する
const keyPair = generateKeyPairSync('ec', {
  namedCurve: 'P-256',
});

/**
 * DPoP Proof JWT を生成するヘルパー関数。
 * @param {string} method - HTTP メソッド（例: 'POST', 'GET'）。
 * @param {string} url - リクエストの完全な URL。
 * @param {string} [nonce] - サーバーから取得するオプションの DPoP-Nonce 値。
 * @param {string} [accessToken] - 'ath' クレームのハッシュ化に使用するオプションのアクセストークン。
 * @returns {string} 署名済みの DPoP Proof JWT。
 */
function generateDPoPHeader(method, url, nonce) {
  const jti = randomBytes(16).toString('base64url');
  const jwk = keyPair.publicKey.export({ format: 'jwk' });
  return jwt.sign({
      jti,
      htm: method,
      htu: url,
      iat: Date.now() / 1000,
      nonce
    },
    keyPair.privateKey,
    {
      algorithm: 'ES256',
      header: {
        typ: 'dpop+jwt',
        jwk,
      },
    });
  }

// 最初は nonce なしでアクセストークンをリクエストする 
async function getTokens(nonce) {
  const response = await fetch('https://[TENANT]/oauth/token', {
      method: 'POST',
      body: new URLSearchParams({
        grant_type: '...',
        client_id: '...',
        // その他のボディパラメーターをここに記述
      }),
      headers: {
        "Content-Type": "application/x-www-form-urlencoded",
        dpop: generateDPoPHeader('POST', 'https://[TENANT]/oauth/token', nonce),
      }
    });

  const result = await response.json();
  return { response, result };
}

// 初回のトークンリクエスト時は nonce を持っていない
let { response, result } = await getTokens(); 
console.log('Initial token request result:', result);

if (response.status === 400 && result.error === 'use_dpop_nonce') {
  const nonce = response.headers.get('dpop-nonce');

  console.log('Received nonce:', nonce);

  // nonce を使用して再試行する
  ({ response, result } = await getTokens(nonce)); 

  console.log('Tokens received:', result);
}
```

<div id="step-4-auth0-authorization-server-validates-the-dpop-proof-jwt">
  ## ステップ 4: Auth0 認可サーバーが DPoP Proof JWT を検証する
</div>

Auth0 認可サーバーはトークンリクエストを受信すると、次の処理を行います。

* DPoP Proof JWT、その公開鍵、署名を抽出します。
* 提供された公開鍵を使用して署名を検証します。
* `htm`、`htu`、`jti,`、`iat` の各クレームを検証します。
* 有効な場合は、アクセストークンを発行します。Auth0 認可サーバーは、確認用クレーム `cnf` をアクセストークンに含めます。`cnf` クレームには、DPoP Proof JWT から取得した公開鍵のサムプリント (ハッシュ値) が含まれます。これをアクセストークンに含めることで、Auth0 認可サーバーはアクセストークンをその特定の公開鍵に紐付けます。つまり、アクセストークンに「sender constraint」を適用します。
* トークンレスポンスでは、`Authorization` ヘッダー内の `token_type` を `Bearer` ではなく `DPoP` に設定します。従来、アクセストークンを `Authorization` ヘッダーで渡す場合は `Bearer` に設定されます。しかし、ここでは DPoP を使用して公開鍵に紐付けられたアクセストークンを渡すため、代わりに `DPoP` に設定されます。
* その後、Auth0 認可サーバーは DPoP sender-constrained アクセストークンをクライアントアプリケーションに発行します。

<div id="step-5-client-application-calls-api-with-the-dpop-bound-token-and-dpop-proof-jwt">
  ## ステップ 5: クライアントアプリケーションが DPoP にバインドされたトークンと DPoP Proof JWT を使用して API を呼び出す
</div>

DPoP を強制するリソースサーバーに対するすべての API 呼び出しで、クライアントアプリケーションは、DPoP にバインドされたアクセストークンと新しい DPoP Proof JWT の両方を提示する必要があります。

DPoP は、すべての API リクエストで DPoP Proof JWT を要求することで、秘密鍵を保持するクライアントアプリケーションだけがアクセストークンを使用できるようにします。

新しい API リクエストごとに、クライアントアプリケーションは次の操作を行います。

1. 次のクレームを含む新しい DPoP Proof JWT を生成します。

* `htm` クレームは、`GET` や `POST` などの API リクエストの `HTTP` メソッドです。
* `htu` クレームは、API リクエストの URI です。
* `ath` クレームは、[ステップ 3](#step-3-client-application-requests-a-dpop-bound-token) で受け取った DPoP にバインドされたアクセストークンの、base64url エンコードされた SHA-256 ハッシュです。

2. クライアントの秘密鍵を使用して、新しい DPoP Proof JWT に暗号学的に署名します。

3. `DPoP` 認証スキームを使用して、DPoP にバインドされたアクセストークンを `Authorization` ヘッダーに含めます:

```javascript lines theme={null}
// DPoP スキームは認可サーバーから受け取った token_type に合わせます
Authorization: DPoP {access_token}
```

4. 新たに生成した DPoP Proof JWT を `DPoP` HTTP ヘッダーに含めます:

```http lines theme={null}
DPoP: {new_dpop_proof_jwt}
```

`DPoP` HTTP ヘッダーには、追加の `ath` クレームを含める必要があります。`ath` クレームは、発行されたアクセストークンの SHA256 ハッシュを base64url エンコードしたものです。

リソースサーバーは、次の処理を行います。

* API リクエストを受信し、アクセストークン、DPoP JWT プルーフ、公開鍵、署名を抽出します。
* `jwk` ヘッダー内の公開鍵を使用して、DPoP Proof JWT の署名を検証します。
* `htm`、`htu`、`jti`、`iat`、`ath` の各クレームを検証します。
* DPoP Proof JWT の `jwk` ヘッダーで示された公開鍵が、アクセストークン内の `cnf.jkt` クレームによってそのアクセストークンに関連付けられた公開鍵と一致することを検証します。

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">
  リソースサーバーには `jti` のリプレイ保護を実装する責任があります。すべての Auth0 SDK が標準で `jti` のリプレイ保護を強制するわけではありません。
</Callout>

すべての検証に成功した場合、リソースサーバーはリクエストを認可します。そうでない場合は、リクエストを拒否し、アクセスを拒否します。

次のコードサンプルは、DPoP を使用して Auth0 からアクセストークンを取得し、その後、DPoP にバインドされたアクセストークンを使用して `/userinfo` エンドポイントを呼び出します。

```jsx lines expandable theme={null}
import { generateKeyPairSync, randomBytes, createHash } from 'node:crypto';
import jwt from 'jsonwebtoken';

const keyPair = generateKeyPairSync('ec', {
  namedCurve: 'P-256',
});

function hashToken(token) {
  return createHash('sha256').update(token).digest('base64url');
}

function generateDPoPHeader(method, url, nonce, accessToken) {
  const jti = randomBytes(16).toString('base64url');
  const jwk = keyPair.publicKey.export({ format: 'jwk' });
  return jwt.sign({
      jti,
      htm: method,
      htu: url,
      iat: Date.now() / 1000,
      nonce,

      // オプションで、アクセストークンのハッシュを含む `ath` クレームを含める
      ...(accessToken ? { ath: hashToken(accessToken) } : {}),
    },
    keyPair.privateKey,
    {
      algorithm: 'ES256',
      header: {
        typ: 'dpop+jwt',
        jwk,
      },
    });
  }

async function getTokens(nonce) {
  const response = await fetch('https://[TENANT]/oauth/token', {
      method: 'POST',
      body: new URLSearchParams({
        grant_type: '...',
        client_id: '...',
        // その他のボディパラメーターをここに記述
      }),
      headers: {
        "Content-Type": "application/x-www-form-urlencoded",
        dpop: generateDPoPHeader('POST', 'https://test1.local.dev.auth0.com/oauth/token', nonce),
      }
    });

  const result = await response.json();
  return { response, result };
}

// 初回実行時はnonceがない
let { response, result } = await getTokens(); 
console.log('Initial token request result:', result);

if (response.status === 400 && result.error === 'use_dpop_nonce') {
  const nonce = response.headers.get('dpop-nonce');
  console.log('Received nonce:', nonce);
  ({ response, result } = await getTokens(nonce)); // nonceを使ってリトライ
  console.log('Tokens received:', result);
}

// DPoPを使って /userinfo を呼び出す
const userInfoResponse = await fetch('https://[TENANT]/userinfo', {
  method: 'GET',
  headers: {
    // DPoP認可スキームを使ってアクセストークンを渡す
    Authorization: `DPoP ${result.access_token}`,

    // DPoPヘッダーを含める（今回はアクセストークンのハッシュ付き）
    dpop: generateDPoPHeader('GET', 'https://[TENANT]/userinfo', nonce, result.access_token),
  },
});

console.log('User info response status:', userInfoResponse.status);
console.log('User info result:', await userInfoResponse.json());
```

<div id="step-6-handle-token-refresh-with-dpop">
  ## ステップ 6: DPoP を使用したトークンの更新を処理する
</div>

DPoP にバインドされたアクセストークンの有効期限が切れた場合は、<Tooltip tip="リフレッシュトークン: ユーザーに再度ログインさせることなく、新しいアクセストークンを取得するために使用されるトークン。" cta="用語集を見る" href="/ja/docs/glossary?term=refresh+token">リフレッシュトークン</Tooltip>を使用して新しいアクセストークンを取得できます。リフレッシュトークンリクエストでは、元のトークンリクエストで使用したものと同じキーペアを使って生成した DPoP Proof JWT が必要です。

以下では、Auth0 における DPoP を使用したリフレッシュトークンフローについて説明します。

クライアントアプリケーションは次の処理を行います。

* Auth0 認可サーバーの `/token` エンドポイントにリフレッシュトークンリクエストを送信します。
* リフレッシュトークンリクエスト用の DPoP Proof JWT を生成します ([ステップ 2](#step-2-client-application-creates-a-dpop-proof-jwt) と同様ですが、`htm` は `POST`、`htu` は<Tooltip tip="トークンエンドポイント: 認可サーバー上で、プログラムからトークンをリクエストするために使用されるエンドポイント。" cta="用語集を見る" href="/ja/docs/glossary?term=token+endpoint">トークンエンドポイント</Tooltip>の URI です) 。
* `DPoP` HTTP ヘッダーに DPoP Proof JWT を含めます。

Auth0 認可サーバーは次の処理を行います。

* DPoP Proof JWT を検証し ([ステップ 4](#step-4-auth0-authorization-server-validates-the-dpop-proof-jwt) と同様) 、新しい DPoP にバインドされたアクセストークンを発行します。

<div id="important-considerations">
  ## 重要な考慮事項
</div>

クライアントアプリケーションに DPoP を実装する際は、次の点を考慮してください。

* **秘密鍵のセキュリティ:** DPoP 実装のセキュリティはクライアントの秘密鍵の保護に依存するため、不正アクセスから確実に保護する必要があります。秘密鍵は、ハードウェアに裏打ちされた保存領域で生成および保管し、エクスポート不可に設定する必要があります。
* **リプレイ保護 (**`jti`\*\* および **`dpop-nonce`**):\*\* DPoP Proof JWT の `jti` クレームは、[`/userinfo`](https://auth0.com/docs/api/authentication/user-profile/get-user-info) エンドポイントなどの保護対象リソースに対するリプレイ攻撃の防止に役立ちます。Auth0 認可サーバーはレスポンスで `DPoP-Nonce` HTTP ヘッダーを返します。パブリッククライアントは、リプレイ保護を強化するため、後続の DPoP Proof JWT にこれを `nonce` クレームとして含める必要があります。
* **レート制限:** DPoP のチャレンジレスポンスフローでは、最初のリクエストの後に、サーバーから提供された nonce を付けて再試行が必要になる場合があるため、各やり取りは実質的に [Auth0 テナントのレート制限](https://auth0.com/docs/troubleshoot/customer-support/operational-policies/rate-limit-policy) に対して 2 リクエスト分としてカウントされます。アプリケーションのリクエスト量がこのオーバーヘッドを考慮していることを確認してください。
* **エラー処理:** `invalid_dpop_proof` や `use_dpop_nonce` など、Auth0 認可サーバーまたはリソースサーバーから返される DPoP 固有のエラーを処理するロジックは、お客様側で実装する必要があります。
* **クライアントの種類:** クライアントシークレットを安全に保存できない、シングルページアプリケーション (SPA) やモバイルアプリなどのパブリッククライアントでは DPoP を使用してください。<Tooltip tip="Confidential Client: 信頼できるバックエンドサーバーを使用して認証情報を安全に保持できるクライアント（アプリケーション）。例としては、安全なバックエンドを備えた Web アプリケーションや、マシン間 (M2M) アプリケーションがあります。" cta="用語集を表示" href="/ja/docs/glossary?term=confidential+clients">機密クライアント</Tooltip>では、クライアントシークレットを持つバックエンドサービスなどに対して DPoP は追加のセキュリティ層となりますが、すでに他の sender-constraining の仕組みがあります。
* **パフォーマンス:** API 呼び出しごとに DPoP Proof JWT を生成して署名するとわずかなオーバーヘッドが生じるため、クライアントアプリケーションの暗号処理が効率的であることを確認してください。
* **鍵のローテーション:** セキュリティを強化するために、DPoP キーペアをローテーションする戦略を実装してください。同じセッションでは同じキーペアを使用するようにしてください。
* **永続化:** セッションを維持し、DPoP にバインドされたアクセストークンを再利用する必要があるクライアントアプリケーション (長期間動作する SPA など) では、最初に生成したキーペアをアプリケーションの再読み込み後も安全に保存し、再取得できるようにしてください。新しいキーペアが生成されたり、別のキーペアが使用されたりすると、DPoP にバインドされたアクセストークンは無効になります。これは、そのトークンが元のキーペアの公開鍵に暗号学的に結び付けられているためです。たとえば、ブラウザーの `IndexedDB` やモバイルアプリのセキュアストレージにキーペアを保存できます。

<div id="learn-more">
  ## 詳細情報
</div>

* [送信者制約を設定する](/ja/docs/secure/sender-constraining/configure-sender-constraining)
