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

> このガイドでは、express-openid-connect SDK を使用して、Express.js の Web アプリケーションに Auth0 を統合し、認証を追加して、ユーザープロファイル情報を表示する方法を説明します。

# Express アプリケーションにログインを追加

export const HowToSchema = () => <script type="application/ld+json">
    {'{"@context":"https://schema.org","@type":"HowTo"}'}
  </script>;

export const CreateInteractiveApp = ({placeholderText = "Auth0", appType = "regular_web", allowedCallbackUrls = ["localhost:3000"], allowedLogoutUrls = ["localhost:3000"], allowedOriginUrls = ["localhost:3000"]}) => {
  const [isAuthenticated, setIsAuthenticated] = useState(false);
  const [storeReady, setStoreReady] = useState(false);
  const [displayForm, setDisplayForm] = useState(true);
  useEffect(() => {
    const init = () => setStoreReady(true);
    if (window.rootStore) {
      window.rootStore.clientStore.setSelectedClient(null);
      window.rootStore.clientStore.setSelectedClientSecret(undefined);
      init();
    } else {
      window.addEventListener("adu:storeReady", init);
    }
    return () => {
      window.removeEventListener("adu:storeReady", init);
    };
  }, []);
  useEffect(() => {
    if (!storeReady) return;
    const disposer = autorun(() => {
      const rootStore = window.rootStore;
      setIsAuthenticated(rootStore.sessionStore.isAuthenticated);
    });
    return () => {
      disposer();
    };
  }, [storeReady]);
  if (!storeReady || typeof window === "undefined" || !displayForm) {
    return <></>;
  }
  const login = () => {
    const baseUrl = window.rootStore.config.apiBaseUrl;
    const returnTo = encodeURIComponent(window.location.href);
    window.location.href = `${baseUrl}/auth/user/login?returnTo=${returnTo}`;
  };
  const Card = ({className = "", children}) => {
    return <div className={`
          flex border rounded-2xl
          border-gray-950/10 dark:border-white/10
          py-3.5 px-4 gap-2
          text-sm text-gray-900 dark:text-gray-200
          ${className}
        `}>
        {children}
      </div>;
  };
  const Button = ({children, ...props}) => {
    return <button className="bg-[--button-primary] text-[--foreground-inverse] px-[1.125rem] py-1.5 rounded-lg font-medium" {...props}>
        {children}
      </button>;
  };
  const CreateApplicationForm = () => {
    const [name, setName] = useState("");
    const [isLoading, setIsLoading] = useState(false);
    const [error, setError] = useState("");
    const handleSubmit = async () => {
      if (!name.trim()) {
        setError("アプリケーション名は必須です");
        return;
      }
      setIsLoading(true);
      setError(null);
      try {
        await window.rootStore.clientStore.createClient({
          name: name.trim(),
          app_type: appType,
          callbacks: allowedCallbackUrls,
          allowed_logout_urls: allowedLogoutUrls,
          web_origins: allowedOriginUrls,
          client_metadata: {
            created_by: "quickstart-docs-app-creation-component"
          }
        });
        setDisplayForm(false);
      } catch (err) {
        console.error("クライアントの作成中にエラーが発生しました:", err);
        const errorMessage = err instanceof Error ? err.message : "アプリケーションの作成に失敗しました";
        setError(errorMessage);
      } finally {
        setIsLoading(false);
      }
    };
    return <Card className="flex-col items-start p-4 gap-3.75">
        <span className="font-medium text-gray-900 dark:text-gray-200">Auth0 アプリの作成</span>
        <div className="w-full flex gap-2">
          <input id="app-name" name={name} className="
              w-full max-w-[448px] h-11 py-2 px-4 
              border rounded-lg border-gray-950/10 dark:border-white/10 
              text-gray-900 dark:text-gray-200
              focus:outline-none dark:focus:outline-none
            " placeholder={`My ${placeholderText} App`} value={name} onChange={e => setName(e.target.value)} />
          <Button onClick={handleSubmit}>{isLoading ? "作成中..." : "作成"}</Button>
        </div>
        {error && <p className="text-red-500">{error}</p>}
      </Card>;
  };
  const SignInForm = () => {
    return <Card className="items-center">
        <Button onClick={login}>ログイン</Button> <span>してアプリを作成してください</span>
      </Card>;
  };
  return isAuthenticated ? <CreateApplicationForm /> : <SignInForm />;
};

<HowToSchema />

<Accordion title="AI を使って Auth0 を統合する" icon="microchip-ai" iconType="solid" defaultOpen>
  Claude Code、Cursor、GitHub Copilot などの AI コーディングアシスタントを使用している場合は、[agent skills](https://agentskills.io/home) を使って、数分で Auth0 認証を自動的に追加できます。

  **インストール:**

  ```bash theme={null}
  npx skills add https://github.com/auth0/agent-skills --skill auth0-express
  ```

  **次に、AI アシスタントに次のように依頼します。**

  ```text theme={null}
  Add Auth0 authentication to my Express app
  ```

  AI アシスタントが、Auth0 アプリケーションの作成、認証情報の取得、`express-openid-connect` のインストール、ミドルウェアの設定、ルートのセットアップを自動的に行います。[agent skills の完全なドキュメント →](/ja/docs/quickstart/agent-skills)
</Accordion>

<Note>
  **前提条件:** 始める前に、次のものがインストールされていることを確認してください。

  * [Node.js](https://nodejs.org/) 18 LTS 以降
  * [npm](https://www.npmjs.com/) 10 以降、または [yarn](https://yarnpkg.com/) 1.22 以降
  * [jq](https://jqlang.github.io/jq/) - Auth0 CLI のセットアップに必要です (省略可)

  **Express のバージョン互換性:** このクイックスタートは Express 4.17.0 以降に対応しています。
</Note>

<div id="get-started">
  ## はじめに
</div>

このガイドでは、`express-openid-connect` SDK を使用して、Express.js の Web アプリケーションに Auth0 を統合し、認証を追加して、ユーザープロファイル情報を表示する方法を紹介します。

***

<div id="1-create-a-new-project">
  ## 1. 新しいプロジェクトを作成する
</div>

Express アプリケーション用の新しいディレクトリを作成し、Node.js プロジェクトを初期化します。

```bash theme={null}
mkdir auth0-express && cd auth0-express
```

```bash theme={null}
npm init -y
```

プロジェクトの構成を作成します。

```bash theme={null}
touch index.js .env
```

***

<div id="2-install-the-auth0-express-sdk">
  ## 2. Auth0 Express SDK をインストールする
</div>

環境変数を管理するために、Express および dotenv とあわせて `express-openid-connect` をインストールします。

```bash theme={null}
npm install express express-openid-connect dotenv
```

開発時は、ファイルの変更に応じてサーバーを自動的に再起動するために、nodemon をインストールします。

```bash theme={null}
npm install --save-dev nodemon
```

`package.json` を更新して、起動スクリプトを追加します。

📁 **package.json**

```json theme={null}
{
  "name": "auth0-express",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "start": "node index.js",
    "dev": "nodemon index.js"
  },
  "dependencies": {
    "dotenv": "^16.3.1",
    "express": "^4.18.2",
    "express-openid-connect": "^2.17.1"
  },
  "devDependencies": {
    "nodemon": "^3.0.2"
  }
}
```

***

<div id="3-setup-your-auth0-app">
  ## 3. Auth0 App を設定する
</div>

次に、Auth0 テナントに新しいアプリケーションを作成し、環境変数をプロジェクトに追加します。

これは、CLI コマンドを実行して自動的に行うことも、Dashboard で手動で行うこともできます。

<Tabs>
  <Tab title="CLI">
    次のシェルコマンドをプロジェクトのルートディレクトリで実行し、Auth0 アプリケーションを作成して `.env` ファイルを生成します。

    **macOS / Linux:**

    ```bash theme={null}
    AUTH0_APP_NAME="My Express App" && \
    auth0 apps create -n "${AUTH0_APP_NAME}" -t regular \
      --callbacks http://localhost:3000 \
      --logout-urls http://localhost:3000 \
      --json | jq -r '"ISSUER_BASE_URL=https://\(.domain)\nCLIENT_ID=\(.client_id)\nSECRET='$(openssl rand -hex 32)'\nBASE_URL=http://localhost:3000"' > .env
    ```

    **Windows (PowerShell):**

    ```powershell theme={null}
    $appName = "My Express App"
    auth0 apps create -n $appName -t regular `
      --callbacks http://localhost:3000 `
      --logout-urls http://localhost:3000 `
      --json | ConvertFrom-Json | ForEach-Object {
        "ISSUER_BASE_URL=https://$($_.domain)`nCLIENT_ID=$($_.client_id)`nSECRET=$([guid]::NewGuid().ToString())`nBASE_URL=http://localhost:3000"
      } | Out-File .env -Encoding utf8
    ```

    <Note>
      Auth0 CLI をまだインストールしていない場合は、次を実行します。

      ```bash theme={null}
      brew tap auth0/auth0-cli && brew install auth0
      ```

      その後、`auth0 login` で認証します。
    </Note>
  </Tab>

  <Tab title="Dashboard">
    1. [Auth0 Dashboard](https://manage.auth0.com/dashboard/) に移動します
    2. **Applications** → **Create Application** に進みます
    3. アプリケーションの名前を入力します (例: "My Express App")
    4. **Regular Web Applications** を選択し、**Create** をクリックします
    5. **Settings** タブで、次のように設定します。

    | 設定                    | 値                       |
    | --------------------- | ----------------------- |
    | Allowed Callback URLs | `http://localhost:3000` |
    | Allowed Logout URLs   | `http://localhost:3000` |

    6. 下にスクロールして **Save Changes** をクリックします
    7. **Basic Information** セクションから **Domain** と **Client ID** の値をコピーします

    次の値で `.env` ファイルを作成します。

    📁 **.env**

    ```bash theme={null}
    ISSUER_BASE_URL=https://YOUR_AUTH0_DOMAIN
    CLIENT_ID=YOUR_CLIENT_ID
    SECRET=use-a-long-random-string-at-least-32-characters
    BASE_URL=http://localhost:3000
    ```

    <Warning>
      `YOUR_AUTH0_DOMAIN` は Auth0 テナントのドメイン (例: `dev-abc123.us.auth0.com`) に、`YOUR_CLIENT_ID` は Dashboard のアプリケーションの Client ID に置き換えてください。
    </Warning>

    セッション暗号化に使用する安全なシークレットを生成します。

    ```bash theme={null}
    openssl rand -hex 32
    ```

    出力をコピーし、`.env` ファイルの `SECRET` の値として使用します。
  </Tab>
</Tabs>

***

<div id="4-configure-the-middleware">
  ## 4. ミドルウェアを設定する
</div>

Auth0 ミドルウェアを Express アプリケーションに追加します。`auth()` ミドルウェアはセッションを管理し、`/login`、`/logout`、`/callback` ルートを自動的に作成します。

📁 **index.js**

```javascript theme={null}
require('dotenv').config();
const express = require('express');
const { auth } = require('express-openid-connect');

const app = express();
const port = process.env.PORT || 3000;

// Auth0 設定
const config = {
  authRequired: false,      // 公開ルートを許可する
  auth0Logout: true,        // Auth0 のログアウトエンドポイントを使用する
  secret: process.env.SECRET,
  baseURL: process.env.BASE_URL,
  clientID: process.env.CLIENT_ID,
  issuerBaseURL: process.env.ISSUER_BASE_URL,
};

// 認証ミドルウェアを適用する
app.use(auth(config));

// ホームルート - 公開
app.get('/', (req, res) => {
  res.send(req.oidc.isAuthenticated() ? 'Logged in' : 'Logged out');
});

app.listen(port, () => {
  console.log(`Server running at http://localhost:${port}`);
});
```

**この設定で行われること:**

* `authRequired: false` を設定すると、認証の有無にかかわらず、デフォルトですべてのユーザーがルートにアクセスできます
* `auth0Logout: true` を設定すると、ユーザーはアプリだけでなく Auth0 からもログアウトされます
* ミドルウェアにより、`/login`、`/logout`、`/callback` のルートが自動的に自動的に追加されます
* ユーザーセッションは暗号化された Cookie に保存されます

***

<div id="5-create-login-logout-and-profile-routes">
  ## 5. ログイン、ログアウト、ユーザープロファイル用のルートを作成する
</div>

次に、ログイン/ログアウトのリンクと、保護されたユーザープロファイルページを表示するルートを追加します。

📁 **index.js**

```javascript theme={null}
require('dotenv').config();
const express = require('express');
const { auth, requiresAuth } = require('express-openid-connect');

const app = express();
const port = process.env.PORT || 3000;

// Auth0 設定
const config = {
  authRequired: false,
  auth0Logout: true,
  secret: process.env.SECRET,
  baseURL: process.env.BASE_URL,
  clientID: process.env.CLIENT_ID,
  issuerBaseURL: process.env.ISSUER_BASE_URL,
};

// 認証ミドルウェアを適用
app.use(auth(config));

// ホームルート - ログイン/ログアウトの状態を表示
app.get('/', (req, res) => {
  const isAuthenticated = req.oidc.isAuthenticated();

  res.send(`
    <html>
      <head>
        <title>Auth0 Express Quickstart</title>
        <style>
          body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; padding: 2rem; max-width: 600px; margin: 0 auto; }
          a { color: #0066cc; text-decoration: none; margin-right: 1rem; }
          a:hover { text-decoration: underline; }
          .status { padding: 1rem; border-radius: 4px; margin: 1rem 0; }
          .logged-in { background: #d4edda; color: #155724; }
          .logged-out { background: #f8d7da; color: #721c24; }
        </style>
      </head>
      <body>
        <h1>Auth0 Express Quickstart</h1>
        <div class="status ${isAuthenticated ? 'logged-in' : 'logged-out'}">
          ${isAuthenticated ? '✓ You are logged in' : '✗ You are logged out'}
        </div>
        <nav>
          ${isAuthenticated
            ? '<a href="/profile">Profile</a> | <a href="/logout">Logout</a>'
            : '<a href="/login">Login</a>'}
        </nav>
      </body>
    </html>
  `);
});

// 保護されたプロファイルルート - 認証が必要
app.get('/profile', requiresAuth(), (req, res) => {
  const user = req.oidc.user;

  res.send(`
    <html>
      <head>
        <title>Profile - Auth0 Express</title>
        <style>
          body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; padding: 2rem; max-width: 600px; margin: 0 auto; }
          a { color: #0066cc; text-decoration: none; }
          img { border-radius: 50%; }
          pre { background: #f4f4f4; padding: 1rem; border-radius: 4px; overflow-x: auto; }
          .card { border: 1px solid #ddd; border-radius: 8px; padding: 1.5rem; margin: 1rem 0; }
        </style>
      </head>
      <body>
        <h1>User Profile</h1>
        <div class="card">
          ${user.picture ? `<img src="${user.picture}" alt="Profile" width="80" />` : ''}
          <h2>${user.name || user.nickname || 'User'}</h2>
          <p><strong>Email:</strong> ${user.email || 'N/A'}</p>
        </div>
        <h3>Full User Object</h3>
        <pre>${JSON.stringify(user, null, 2)}</pre>
        <nav>
          <a href="/">← Back to Home</a> | <a href="/logout">Logout</a>
        </nav>
      </body>
    </html>
  `);
});

app.listen(port, () => {
  console.log(`Server running at http://localhost:${port}`);
});
```

**要点:**

* `requiresAuth()` ミドルウェアは `/profile` ルートを保護し、未認証のユーザーをログイン画面にリダイレクトします
* `req.oidc.user` には、認証済みユーザーのユーザープロファイル情報が含まれています
* `req.oidc.isAuthenticated()` は、ログイン状態を示すブール値を返します
* ログインおよびログアウトのルート (`/login`、`/logout`) は、`auth()` ミドルウェアによって自動的に作成されます

***

<div id="6-run-your-app">
  ## 6. アプリを実行する
</div>

開発サーバーを起動します。

```bash theme={null}
npm run dev
```

ブラウザで [http://localhost:3000](http://localhost:3000) を開きます。

<Check>
  **チェックポイント**

  これで、正しく動作する Auth0 のログインページが表示されるはずです。次のことを確認してください。

  1. "Login" をクリックする - Auth0 の Universal Login ページにリダイレクトされます
  2. 認証を完了する - アプリにリダイレクトされます
  3. "/profile" にアクセスする - ユーザー情報が表示されます
  4. "Logout" をクリックする - アプリと Auth0 の両方からログアウトされます
</Check>

***

<div id="advanced-usage">
  ## 応用
</div>

<AccordionGroup>
  <Accordion title="requiresAuth() で特定のルートを保護する">
    認証が必要な個々のルートを保護するには、`requiresAuth()` ミドルウェアを使用します。

    ```javascript theme={null}
    const { auth, requiresAuth } = require('express-openid-connect');

    app.use(auth({ authRequired: false }));

    // パブリックルート
    app.get('/', (req, res) => {
      res.send('Welcome! This is public.');
    });

    // 保護されたルート
    app.get('/dashboard', requiresAuth(), (req, res) => {
      res.send(`Hello ${req.oidc.user.name}, welcome to your dashboard!`);
    });

    app.get('/settings', requiresAuth(), (req, res) => {
      res.send('Settings page - only for authenticated users');
    });
    ```

    Express Router を使用して、特定のパス配下にあるすべてのルートを保護することもできます。

    ```javascript theme={null}
    const protectedRouter = express.Router();

    // このルーター内のすべてのルートで認証が必要
    protectedRouter.use(requiresAuth());

    protectedRouter.get('/dashboard', (req, res) => {
      res.send('Protected dashboard');
    });

    protectedRouter.get('/settings', (req, res) => {
      res.send('Protected settings');
    });

    app.use('/app', protectedRouter);
    // ルート: /app/dashboard、/app/settings はすべて保護済み
    ```
  </Accordion>

  <Accordion title="アクセストークンを使用した保護されたAPIの呼び出し">
    アクセストークンが必要な外部 API を呼び出すには、SDK を設定してアクセストークンを取得するようにします。

    📁 **index.js** (更新後の設定)

    ```javascript theme={null}
    const config = {
      authRequired: false,
      auth0Logout: true,
      secret: process.env.SECRET,
      baseURL: process.env.BASE_URL,
      clientID: process.env.CLIENT_ID,
      issuerBaseURL: process.env.ISSUER_BASE_URL,
      clientSecret: process.env.CLIENT_SECRET,  // 認可コードフローで必要
      authorizationParams: {
        response_type: 'code',
        audience: process.env.API_AUDIENCE,     // 使用する API の識別子
        scope: 'openid profile email read:data',
      },
    };
    ```

    これらを `.env` ファイルに追加します。

    ```bash theme={null}
    CLIENT_SECRET=your_client_secret_from_dashboard
    API_AUDIENCE=https://your-api.example.com
    ```

    次に、アクセストークンを使用して API を呼び出します。

    ```javascript theme={null}
    app.get('/api-data', requiresAuth(), async (req, res) => {
      try {
        let { token_type, access_token, isExpired, refresh } = req.oidc.accessToken;

        // トークンの有効期限が切れている場合は更新する
        if (isExpired()) {
          const refreshed = await refresh();
          access_token = refreshed.access_token;
        }

        // 保護されたAPIを呼び出す
        const response = await fetch('https://your-api.example.com/data', {
          headers: {
            Authorization: `${token_type} ${access_token}`,
          },
        });

        const data = await response.json();
        res.json(data);
      } catch (error) {
        console.error('API call failed:', error);
        res.status(500).json({ error: 'Failed to fetch data' });
      }
    });
    ```

    <Note>
      リフレッシュトークンを取得するには、scope に `offline_access` を追加します。

      ```javascript theme={null}
      scope: 'openid profile email offline_access read:data',
      ```
    </Note>
  </Accordion>

  <Accordion title="クレームベース認可の使用">
    ユーザーのクレーム (ロールや権限など) に基づいてルートを保護します:

    ```javascript theme={null}
    const { auth, requiresAuth, claimEquals, claimIncludes, claimCheck } = require('express-openid-connect');

    app.use(auth({ authRequired: false }));

    // role = 'admin' のユーザーのみ
    app.get('/admin', claimEquals('role', 'admin'), (req, res) => {
      res.send('Admin dashboard');
    });

    // roles 配列に 'editor' が含まれるユーザー
    app.get('/editor', claimIncludes('roles', 'editor'), (req, res) => {
      res.send('Editor dashboard');
    });

    // カスタムクレームチェック（ロジックあり）
    app.get('/premium', claimCheck((req, claims) => {
      return claims.subscription === 'premium' || claims.role === 'admin';
    }), (req, res) => {
      res.send('Premium content');
    });
    ```

    <Note>
      `role` のようなクレームは、Auth0 の Rules または Actions を使用してトークンに追加する必要があります。[カスタムクレームを追加する方法の詳細はこちら](https://auth0.com/docs/customize/actions/flows-and-triggers/login-flow/add-user-roles-to-id-and-access-tokens)。
    </Note>
  </Accordion>

  <Accordion title="カスタムセッションストア (Redis)">
    本番環境や複数のサーバーインスタンスを実行する場合は、カスタムのセッションストアを使用してください。

    ```bash theme={null}
    npm install redis connect-redis
    ```

    ```javascript theme={null}
    const { auth } = require('express-openid-connect');
    const { createClient } = require('redis');
    const RedisStore = require('connect-redis').default;

    // Redisクライアントを作成
    const redisClient = createClient({
      url: process.env.REDIS_URL || 'redis://localhost:6379',
    });
    redisClient.connect().catch(console.error);

    const config = {
      authRequired: false,
      auth0Logout: true,
      secret: process.env.SECRET,
      baseURL: process.env.BASE_URL,
      clientID: process.env.CLIENT_ID,
      issuerBaseURL: process.env.ISSUER_BASE_URL,
      session: {
        store: new RedisStore({ client: redisClient }),
      },
    };

    app.use(auth(config));
    ```

    **カスタムセッションストアを使用すべきケース:**

    * 複数のサーバーインスタンスを運用している場合 (ロードバランシング)
    * セッションデータが Cookie のサイズ制限 (約4KB) を超える場合
    * サーバーの再起動後もセッションを保持する必要がある場合
    * バックチャネルログアウトを使用している場合
  </Accordion>

  <Accordion title="エラー処理">
    認証エラーに対する適切なエラー処理を追加します。

    ```javascript theme={null}
    const { auth } = require('express-openid-connect');

    app.use(auth({
      authRequired: false,
      auth0Logout: true,
      secret: process.env.SECRET,
      baseURL: process.env.BASE_URL,
      clientID: process.env.CLIENT_ID,
      issuerBaseURL: process.env.ISSUER_BASE_URL,
      errorOnRequiredAuth: true,  // APIルートではリダイレクトの代わりに401を返す
    }));

    // Custom error handler
    app.use((err, req, res, next) => {
      // Handle authentication errors
      if (err.statusCode === 401) {
        // For API requests, return JSON
        if (req.accepts('json')) {
          return res.status(401).json({
            error: 'Authentication required',
            login_url: '/login',
          });
        }
        // For browser requests, redirect to login
        return res.redirect('/login');
      }

      // Log the error (don't expose details to client)
      console.error('Application error:', err.message);

      res.status(err.statusCode || 500).json({
        error: 'An unexpected error occurred',
      });
    });
    ```
  </Accordion>
</AccordionGroup>

***

<div id="troubleshooting">
  ## トラブルシューティング
</div>

<AccordionGroup>
  <Accordion title="よくある問題と解決策">
    ### ログイン後の「Invalid state」エラー

    **問題:** 認証リクエストとコールバックで state が一致していません。

    **解決策:**

    1. 本番環境では HTTPS を使用していることを確認します
    2. Cookie が正しく設定されていることを確認します (ブラウザーでブロックされていないこと)
    3. Auth0 Dashboard でコールバック URL が完全に一致していることを確認します

    ### 「req.oidc is undefined」

    **問題:** `req.oidc` にアクセスする前に `auth()` ミドルウェアが適用されていません。

    **解決策:** `req.oidc` にアクセスするルートより前で `app.use(auth(config))` が呼び出されていることを確認します。

    ```javascript theme={null}
    // ✅ 正しい順序
    app.use(auth(config));
    app.get('/profile', requiresAuth(), (req, res) => { ... });

    // ❌ 間違った順序
    app.get('/profile', requiresAuth(), (req, res) => { ... });
    app.use(auth(config));
    ```

    ### セッションが大きすぎる / Cookie エラー

    **問題:** ユーザーセッションデータが Cookie のサイズ制限を超えています。

    **解決策:** Redis などのカスタムセッションストアを使用します。

    ```javascript theme={null}
    session: {
      store: new RedisStore({ client: redisClient }),
    }
    ```

    ### コールバック URL の不一致

    **問題:** Auth0 から「Callback URL mismatch」エラーが返されます。

    **解決策:**

    1. Auth0 Dashboard → Applications → Your App → Settings に移動します
    2. **Allowed Callback URLs** に `http://localhost:3000` (または本番環境の URL) を追加します
    3. URL は **完全に** 一致している必要があります (末尾のスラッシュを含む)

    ### 環境変数が読み込まれない

    **問題:** 設定値が `undefined` です。

    **解決策:**

    1. `require('dotenv').config()` がエントリーファイルの先頭にあることを確認します
    2. `.env` ファイルがルートディレクトリにあることを確認します
    3. 変数名にタイプミスがないか確認します

    ```javascript theme={null}
    // デバッグ: 設定値をログに出力します（本番環境では削除してください！）
    console.log('Config check:', {
      hasSecret: !!process.env.SECRET,
      hasClientID: !!process.env.CLIENT_ID,
      issuerBaseURL: process.env.ISSUER_BASE_URL,
    });
    ```
  </Accordion>
</AccordionGroup>

***

<div id="next-steps">
  ## 次のステップ
</div>

認証が動作するようになったら、次の内容も確認してください。

* **[認可を追加する](https://auth0.com/docs/manage-users/access-control/rbac)** - ロールベースアクセス制御を実装します
* **[保護された API を呼び出す](https://auth0.com/docs/secure/tokens/access-tokens/get-access-tokens)** - アクセストークンを使用してバックエンド API を呼び出します
* **[Universal Login をカスタマイズする](https://auth0.com/docs/customize/universal-login-pages)** - ログイン画面をブランドに合わせてカスタマイズします
* **[ソーシャル接続を追加する](https://auth0.com/docs/connections/social)** - Google、GitHub などのソーシャルログインを有効にします
* **[MFA を実装する](https://auth0.com/docs/secure/multi-factor-authentication)** - 多要素認証を追加します

***

<div id="resources">
  ## リソース
</div>

* **[express-openid-connect GitHub](https://github.com/auth0/express-openid-connect)** - ソースコードとサンプル
* **[API Documentation](https://auth0.github.io/express-openid-connect/)** - API リファレンス全文
* **[Auth0 Express Sample App](https://github.com/auth0-samples/auth0-express-webapp-sample)** - 完全なサンプルアプリケーション
* **[Auth0 Community](https://community.auth0.com/)** - コミュニティでサポートを受ける
