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

# OIDCバックチャネルログアウト

> Auth0のOIDCバックチャネルログアウト機能を説明します。

Auth0は、エンタープライズプランサブスクリプションのすべてのテナントにおいて、[OpenID Connectバックチャネルログアウト1.0仕様](https://openid.net/specs/openid-connect-backchannel-1_0.html#Backchannel)をサポートしています。

この仕様では、IDトークンとログアウトトークンに含まれるセッションID (`sid`)を活用して、バックチャネル通信を介してセッションの終了を調整します。異なるセッションIDは、テナント内のユーザーエージェントまたはデバイスの個々のセッションを表します。ログアウトトークンは、ログアウトするエンドユーザーとセッションを識別します。

## バックチャネル通信

バックチャネルログアウトを使用するには、アプリケーションは、テナントサーバーからアクセス可能なバックチャネルログアウトURIを公開する必要があり、アプリケーションはログアウトトークンを含む要求を受信する必要があります。アプリケーションがこの要求を受信すると、トークン内のクレームと一致するローカルセッション状態をクリアする必要があります。

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">
  バックチャネルログアウトが機能するためには、アプリケーションがバックチャネル通信を受信できなければなりません。
</Callout>

### OIDCバックチャネルログアウト通信のトークン

アプリケーションは、バックチャネル経由で通信が実行されるときに、どのセッションを終了するかを決定するためにセッションクッキーに依存することはできません。むしろ、サービスはIDとログアウトトークンの共有セッション識別子(`sid`)に依存します。

エンドユーザーがログイン時にAuth0で正常に認証されると、認可サーバーはアクセストークンとIDトークンを発行します。ログアウトトークンは、ログアウトアクションやセッションの取り消しなどによってセッションが破棄されたときに生成されます。IDトークンとログアウトトークンの両方に、バックチャネルログアウトワークフローを容易にするためにアプリケーションが必要とするクレームが含まれています。クレームの詳細については、「[JSON Webトークンクレーム](/docs/ja-jp/secure/tokens/json-web-tokens/json-web-token-claims)」をお読みください。

<Frame>
  <img src="https://mintcdn.com/docs-dev-actions-triggers-prototype/dadTd1GKGvbSPiSP/docs/images/ja-jp/cdy7uua7fh8z/5jQ5HogFNeD9tqUGEJuJHE/1ba97db33746ad428299018432e93147/2023-09-29_09-32-00__ja-JP_.png?fit=max&auto=format&n=dadTd1GKGvbSPiSP&q=85&s=3ad9b533516668a91e964390bcae54c2" alt="Workflow for back-channel logout" width="849" height="324" data-path="docs/images/ja-jp/cdy7uua7fh8z/5jQ5HogFNeD9tqUGEJuJHE/1ba97db33746ad428299018432e93147/2023-09-29_09-32-00__ja-JP_.png" />
</Frame>

1. ログイン - ユーザー認証中に、Auth0テナントはIDトークンに`sid`を追加します。
2. ログイン - アプリケーションは、受信したセッション識別子を独自のセッションストアに保存し、それをアプリケーション固有のセッションに関連付けます。
3. ログアウト - IdPは、事前に登録されたログアウトコールバックURLを呼び出し、ログアウトトークンをこのエンドポイントに投稿します。トークンには、`user_id` (`sub`)と`sid`およびその他のパラメーターが含まれます。
4. ログアウト - アプリケーションのバックエンドは、OIDC仕様に従ってログアウトトークンを検証し、`sid`を抽出する必要があります。その後、バックエンドはこのトークンを使用して、識別子に関連付けられたセッションを見つけ、必要に応じてセッションを終了できます。

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">
  ログアウトの成功時に予期される応答は`HTTP 200`です。`HTTP 400`を受け取った場合は、要求が正しくないか、誤って解釈されたと考えられるため、トラブルシューティングのヒントを参考にしてください。詳細については、「[バックチャネルログアウトを構成する](/docs/ja-jp/authenticate/login/logout/back-channel-logout/configure-back-channel-logout)」をお読みください。
</Callout>

### 仕組み

サンプルユースケースでは、バックチャネルログアウトが複数のアプリケーションでどのように機能するかを示します。

<Frame>
  <img src="https://mintcdn.com/docs-dev-actions-triggers-prototype/Sm-rZzBGG9mhReiN/docs/images/ja-jp/cdy7uua7fh8z/54mbNobsvLec0A2tz0DXUG/e9fa0e64b839d7ab0485110b789ac068/2023-06-20_09-39-12.png?fit=max&auto=format&n=Sm-rZzBGG9mhReiN&q=85&s=5674646c947df440897c9fd55e9cca3c" alt="Back-channel logout multiple app use case" width="2476" height="2562" data-path="docs/images/ja-jp/cdy7uua7fh8z/54mbNobsvLec0A2tz0DXUG/e9fa0e64b839d7ab0485110b789ac068/2023-06-20_09-39-12.png" />
</Frame>

1. アプリケーションの構成中に、アプリケーションAはAuth0にバックチャネルログアウトURIを登録します。

2. アプリケーションの構成中に、アプリケーションBはAuth0にバックチャネルログアウトURIを登録します。

   <Callout icon="file-lines" color="#0EA5E9" iconType="regular">
     OIDCのバックチャネルログアウトのURLは、以下の条件を満たさなければなりません。

     * IdPからアクセスできる
     * TLS暗号化されたエンドポイントを使用している
     * [ログアウトトークンを検証する](https://openid.net/specs/openid-connect-backchannel-1_0.html#Validation)
   </Callout>

3. エンドユーザーのログイン時に、ユーザーはAuth0で認証してアプリケーションAにアクセスします。

4. Auth0は、`sid`を含むIDトークンをアプリケーションAに送信します。詳細については、「[IDトークンの構造](/docs/ja-jp/secure/tokens/id-tokens/id-token-structure)」をお読みください。

5. ユーザーはAuth0で認証してアプリケーションBにアクセスします。

6. Auth0は同じ`sid`を含むIDトークンをアプリケーションBに送信します。アプリケーションはセッション情報を保存しなければなりません。

7. ログアウト中に、アプリケーションAまたは他のエンティティがフロントチャネルでログアウトを開始します。

8. Auth0はセッションCookieを介してAuth0セッションレイヤーを終了します。

9. Auth0はアプリケーションAのバックチャネルログアウトURIを呼び出し、ログアウトトークンを投稿します。

10. アプリケーションAはログアウトトークンを検証し、セッションを終了します。

11. Auth0はアプリケーションBのバックチャネルログアウトURIを呼び出し、ログアウトトークンを投稿します。

12. アプリケーションBはログアウトトークンを検証し、セッションを終了します。

#### サンプルトークン

Auth0でログアウトトークンとして使用するには、アプリケーションで<Tooltip data-tooltip-id="react-containers-DefinitionTooltip-3" href="/docs/ja-jp/glossary?term=json-web-token" tip="JSON Web Token（JWT）: 二者間のクレームを安全に表現するために使用される標準IDトークン形式（および多くの場合、アクセストークン形式）。" cta="用語集の表示">JWT</Tooltip>を解析および検証できる必要があります。詳細については、「[JSON Webトークンを検証する](/docs/ja-jp/secure/tokens/json-web-tokens/validate-json-web-tokens)」をお読みください。

アプリケーションがトークンを検証してデコードすると、コンテンツは以下の例のようになります。

```json JSON lines theme={null}
{
  "iss": "https://artex-dev.eu.auth0.com/",
  "sub": "auth0|602e93db83fa6f00749a23e6",
  "aud": "TuhNLv7ulXD3RfyLlSMbOvszzwJJFPpO",
  "iat": 1698160928,
  "exp": 1698161048,
  "jti": "44a91215-dfb4-4dfe-a1eb-fcafa911deba",
  "events": {
    "http://schemas.openid.net/event/backchannel-logout": {}
  },
  "trace_id": "81b336a94a4a5707",
  "sid": "375UIp_ID5mCTClIeBEHpXfGwq51tF_L"
}
```

### Auth0 SDK

完全な例と製品コードは、[express-openid-connect SDK](https://github.com/auth0/express-openid-connect/blob/master/EXAMPLES.md#11-back-channel-logout)の **バックチャネルログアウト例** のセクションにすでに含まれています。

## 実装例

### セッションストレージ

セッションストレージの例はNode (Express)で構築されており、[Express OpenID Connectウェブアプリサンプル](https://github.com/auth0-samples/auth0-express-webapp-sample/tree/master/01-Login)に基づいています。

アプリケーションセッションタブで、ログアウトトークンを受信するように構成したルートを公開します。トークンを検証し、ユーザーセッションを終了します。

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">
  この例では、デモの目的でメモリー内セッションストアを使用しています。
</Callout>

**routes/index.js**

```javascript JavaScript lines expandable theme={null}
const express = require('express');
const router = express.Router();
const { requiresAuth } = require('express-openid-connect');

// middleware to validate the logout token
const requiresValidLogoutToken = require('../middlewares/validateLogoutToken');

// helper function to delete user sessions
const deleteUserSessions = require('../utils/sessions');

// new route to receive backchannel logout tokens
// must be configured in the Application -> Sessions tab 
// in the Auth0 Management Dashboard
router.post(
  '/backchannel-logout',
  requiresValidLogoutToken,
  function (req, res, next) {
    // at this point the logout token is valid, checked by requiresValidLogoutToken middleware
    // you can access it from the request object: req.logoutToken

    // delete user session so the user gets logged out
    deleteUserSessions(
      req.app.locals.sessionStore,
      req.logoutToken.sub,
      req.logoutToken.sid
    );

    res.sendStatus(200);
  }
);

router.get('/', function (req, res, next) {
  res.render('index', {
    title: 'Auth0 Webapp sample Nodejs',
    isAuthenticated: req.oidc.isAuthenticated(),
    headline: process.env.APP_NAME,
    backgroundColor: process.env.BACKGROUND_COLOR,
    baseURL: process.env.BASE_URL,
  });
});

router.get('/profile', requiresAuth(), function (req, res, next) {
  res.render('profile', {
    userProfile: JSON.stringify(req.oidc.user, null, 2),
    title: 'Profile page',
    headline: process.env.APP_NAME,
    backgroundColor: process.env.BACKGROUND_COLOR,
    baseURL: process.env.BASE_URL,
  });
});

module.exports = router;
```

**middlewares/validateLogoutToken.js**

```javascript JavaScript lines expandable theme={null}
// This middleware validates the logout token as defined here:
// https://openid.net/specs/openid-connect-backchannel-1_0.html#Validation

const jose = require('jose');

async function requiresValidLogoutToken(req, res, next) {

  // get remote key set for token verification
  const JWKS = jose.createRemoteJWKSet(
    new URL(process.env.ISSUER_BASE_URL + '/.well-known/jwks.json')
  );

  const logoutToken = req.body.logout_token;

  if (!logoutToken) {
    res.status(400).send('Need logout token');
  }

  try {
    const { payload, protectedHeader } = await jose.jwtVerify(
      logoutToken,
      JWKS,
      {
        issuer: process.env.ISSUER_BASE_URL + '/',
        audience: process.env.CLIENT_ID,
        typ: 'JWT',
        maxTokenAge: '2 minutes',
      }
    );

    // Verify that the Logout token contains a sub claim, a sid claim, or both
    if (!payload.sub && !payload.sid) {
      res
        .status(400)
        .send(
          'Error: Logout token must contain either sub claim or sid claim, or both'
        );
    }

    // Verify that the logout token contains an events claim
    // whose value is a JSON object containing the member name http://schemas.openid.net/event/backchannel-logout
    if (!payload.events['http://schemas.openid.net/event/backchannel-logout']) {
      res
        .status(400)
        .send(
          'Error: Logout token must contain events claim with correct schema'
        );
    }

    // Verify that the Logout token does not contain a nonce claim.
    if (payload.nonce) {
      res
        .status(400)
        .send('Error: Logout token must not contain a nonce claim');
    }

    // attach valid logout token to request object
    req.logoutToken = payload;

    // token is valid, call next middleware
    next();
  } catch (error) {
    res.status(400).send(`Error:  ${error.message}`);
  }
}

module.exports = requiresValidLogoutToken;
```

### ログアウトトークンストア

トークンストレージの一般的なアプローチは、セッションストアモデルの代替としてログアウトストアを定義することです。アプリケーションは、ログアウトトークンのコレクションを永続レベルで保持します。

アプリケーションが認証ステータスを確認する必要があるときは、ログアウトトークンストアを照会して、セッションがまだアクティブかどうかを確認します。ログアウトストアは、必要な情報のみを保持するために、古い情報を定期的にフラッシュします。

<Frame>
  <img src="https://mintcdn.com/docs-dev-actions-triggers-prototype/CVqyjpVc9VVKbCsn/docs/images/ja-jp/cdy7uua7fh8z/2zTtcie1d0fjiSuxZ4huyV/3eedae4e01ef915bcd58ac4de1b861aa/image__21___ja-JP_.png?fit=max&auto=format&n=CVqyjpVc9VVKbCsn&q=85&s=7609121432624f1bd2911d6bb1f0c851" alt="Logout Token Store" width="2978" height="1144" data-path="docs/images/ja-jp/cdy7uua7fh8z/2zTtcie1d0fjiSuxZ4huyV/3eedae4e01ef915bcd58ac4de1b861aa/image__21___ja-JP_.png" />
</Frame>

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

バックチャネルログアウトトークンはインターネット経由で配信されるため、それを受信するコールバックエンドポイントは、信頼性が高く安全な操作を確保するためにベストプラクティスに従う必要があります。以下の推奨事項リストは網羅的なものではなく、常に特定の展開および運用状況を考慮して、それに応じて適応する必要があります。以下のリストでは、バックチャネルログアウトトークンを処理するアプリはすべて「アプリ」と呼ばれています。

* アプリは、ユーザーログイン時に受信したセッションID (`sid` クレーム)を保存し、後でバックチャネルログアウトトークンを受け取ったときに取得できるようにする必要があります。
* アプリは、[JWT検証のベストプラクティス](/docs/ja-jp/secure/tokens/json-web-tokens/validate-json-web-tokens)に従って、受信したトークンを検証する必要があります。
* アプリは、信頼できるテナントによって発行されたトークンのみを受け入れる必要があります。悪意のある人物が他のAuth0テナントによって発行されたトークンを送信しようとする可能性があります。このような試みは拒否しなければなりません。
* アプリは、アプリが認識する`sid`値（セッションID）が含まれている場合にのみトークンを受け入れる必要があります。無効なセッションID（期限切れまたは認識されない）を含むトークンは拒否する必要があります。
* アプリはコールバックエンドポイントをTLS経由でのみ公開する必要があります。暗号化されていない通信チャネルは許可されません。
* アプリは、公開されている[送信IPアドレス](/docs/ja-jp/secure/security-guidance/data-security/allowlist)のリストからの要求のみを受け入れることをお勧めします。
* アプリは、監視、ログ記録、レート制限に関する一般的なベスト プラクティスに従うことが推奨されますが、これらの詳細はこのドキュメントの範囲外です。
* アプリでは、古くなったセッションや期限切れのセッションを定期的にクリーンアップすることをお勧めします。
* ログアウトトークンが常に正しいバックチャネルログアウトコールバックURLに配信されるようにするには、エンドポイントアドレスの変更をテナント構成と同期する必要があります。

## もっと詳しく

* [OIDCバックチャネルログアウトを構成する](/docs/ja-jp/authenticate/login/logout/back-channel-logout/configure-back-channel-logout)
* [ログインとログアウトの問題を確認する](/docs/ja-jp/troubleshoot/authentication-issues/check-login-and-logout-issues)
* [ユーザーをSAML IDプロバイダーからログアウトする](/docs/ja-jp/authenticate/login/logout/log-users-out-of-saml-idps)
* [OIDCエンドポイントを使用してユーザーをAuth0からログアウトさせる](/docs/ja-jp/authenticate/login/logout/log-users-out-of-auth0)
* [アプリケーションからユーザーをログアウトする](/docs/ja-jp/authenticate/login/logout/log-users-out-of-applications)
* [ユーザーをIDプロバイダーからログアウトさせる](/docs/ja-jp/authenticate/login/logout/log-users-out-of-idps)
