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

> ログイン、保護されたルート、ユーザープロフィールを備えた Flask Web アプリケーションに Auth0 認証を追加

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

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

export const AuthCodeGroup = ({children, dropdown}) => {
  const [processedChildren, setProcessedChildren] = useState(children);
  useEffect(() => {
    let unsubscribe = null;
    function init() {
      unsubscribe = window.autorun(() => {
        const processChildren = node => {
          if (typeof node === "string") {
            let processedNode = node;
            for (const [key, value] of window.rootStore.variableStore.values.entries()) {
              const escapedKey = key.replaceAll(/[.*+?^${}()|[\]\\]/g, (String.raw)`\$&`);
              processedNode = processedNode.replaceAll(new RegExp(escapedKey, "g"), value);
            }
            return processedNode;
          } else if (Array.isArray(node)) {
            return node.map(processChildren);
          } else if (node && node.props && node.props.children) {
            return {
              ...node,
              props: {
                ...node.props,
                children: processChildren(node.props.children)
              }
            };
          }
          return node;
        };
        setProcessedChildren(processChildren(children));
      });
    }
    if (window.rootStore) {
      init();
    } else {
      window.addEventListener("adu:storeReady", init);
    }
    return () => {
      window.removeEventListener("adu:storeReady", init);
      unsubscribe?.();
    };
  }, [children]);
  return <CodeGroup dropdown={dropdown}>{processedChildren}</CodeGroup>;
};

<HowToSchema />

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

  * **[Python](https://www.python.org/downloads/)** 3.9 以降
  * **[pip](https://pip.pypa.io/en/stable/installation/)** 20.0 以降
  * **[jq](https://jqlang.org/)** - Auth0 CLI のセットアップに必要です

  **Flask のバージョン互換性:** このクイックスタートでは、非同期サポートのために `[async]` extra を含む **Flask 2.0+** を使用します。
</Note>

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

このクイックスタートでは、Flask アプリケーションに Auth0 認証を追加する方法を説明します。[Auth0 WebApp Python SDK](https://github.com/auth0/auth0-server-python) を使用して、ログイン機能、保護されたルート、ユーザープロフィールへのアクセスを備えたセキュアな Web アプリケーションを構築します。

<Steps>
  <Step title="環境をセットアップする" stepNumber={1}>
    Flask プロジェクト用に新しいディレクトリを作成します。

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

    仮想環境を作成します:

    ```bash theme={null}
    python -m venv venv
    source venv/bin/activate  # Windowsの場合: venv\Scripts\activate
    ```
  </Step>

  <Step title="依存関係をインストール" stepNumber={2}>
    依存関係を管理するための `requirements.txt` を作成します：

    ```txt requirements.txt theme={null}
    auth0-server-python>=1.0.0b7
    flask[async]>=2.0.0
    python-dotenv>=1.0.0
    ```

    `requirements.txt` ファイルには、プロジェクトのすべての依存関係が記載されています。これらをインストールするには、次を実行します:

    ```bash theme={null}
    pip install -r requirements.txt
    ```
  </Step>

  <Step title="Auth0 アプリを設定する" stepNumber={3}>
    次に、Auth0テナントで新しいアプリを作成し、プロジェクトに環境変数を追加します。

    CLIコマンドを実行して自動的に行う方法と、Dashboardから手動で行う方法のいずれかを選択できます。

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

        <CodeGroup>
          ```shellscript Mac theme={null}
          AUTH0_APP_NAME="My Flask App" && brew tap auth0/auth0-cli && brew install auth0 && auth0 login --no-input && auth0 apps create -n "${AUTH0_APP_NAME}" -t regular -c http://localhost:5000/callback -l http://localhost:5000 -o http://localhost:5000 --reveal-secrets --json > app-details.json && CLIENT_ID=$(python3 -c "import json; print(json.load(open('app-details.json'))['client_id'])") && CLIENT_SECRET=$(python3 -c "import json; print(json.load(open('app-details.json'))['client_secret'])") && DOMAIN=$(auth0 tenants list --json | python3 -c "import sys, json; print([t['name'] for t in json.load(sys.stdin) if t.get('active')][0])") && SECRET=$(openssl rand -hex 64) && echo "AUTH0_DOMAIN=${DOMAIN}" > .env && echo "AUTH0_CLIENT_ID=${CLIENT_ID}" >> .env && echo "AUTH0_CLIENT_SECRET=${CLIENT_SECRET}" >> .env && echo "AUTH0_SECRET=${SECRET}" >> .env && echo "AUTH0_REDIRECT_URI=http://localhost:5000/callback" >> .env && rm app-details.json && echo ".env file created with your Auth0 details:" && cat .env
          ```

          ```shellscript Windows theme={null}
          $AppName = "My Flask App"; winget install Auth0.CLI; auth0 login --no-input; auth0 apps create -n "$AppName" -t regular -c http://localhost:5000/callback -l http://localhost:5000 -o http://localhost:5000 --reveal-secrets --json | Set-Content -Path app-details.json; $ClientId = (Get-Content -Raw app-details.json | ConvertFrom-Json).client_id; $ClientSecret = (Get-Content -Raw app-details.json | ConvertFrom-Json).client_secret; $Domain = (auth0 tenants list --json | ConvertFrom-Json | Where-Object { $_.active -eq $true }).name; $Secret = [System.Convert]::ToHexString([System.Security.Cryptography.RandomNumberGenerator]::GetBytes(64)).ToLower(); Set-Content -Path .env -Value "AUTH0_DOMAIN=$Domain"; Add-Content -Path .env -Value "AUTH0_CLIENT_ID=$ClientId"; Add-Content -Path .env -Value "AUTH0_CLIENT_SECRET=$ClientSecret"; Add-Content -Path .env -Value "AUTH0_SECRET=$Secret"; Add-Content -Path .env -Value "AUTH0_REDIRECT_URI=http://localhost:5000/callback"; Remove-Item app-details.json; Write-Output ".env file created with your Auth0 details:"; Get-Content .env
          ```
        </CodeGroup>
      </Tab>

      <Tab title="Dashboard">
        始める前に、プロジェクトのルートに `.env` ファイルを作成します。

        ```bash .env theme={null}
        # Auth0 設定
        AUTH0_DOMAIN=YOUR_AUTH0_DOMAIN
        AUTH0_CLIENT_ID=YOUR_CLIENT_ID
        AUTH0_CLIENT_SECRET=YOUR_CLIENT_SECRET
        AUTH0_SECRET=YOUR_GENERATED_SECRET
        AUTH0_REDIRECT_URI=http://localhost:5000/callback
        ```

        1. [Auth0 Dashboard](https://manage.auth0.com/dashboard/) → **Applications** → **Applications** に移動します
        2. **Create Application** をクリックします
        3. アプリケーションに名前を付け (例: "My Flask App") 、**Regular Web Application** を選択します
        4. **Create** をクリックします
        5. **Settings** タブで次の項目を設定します。
           * **Allowed Callback URLs**: `http://localhost:5000/callback`
           * **Allowed Logout URLs**: `http://localhost:5000`
           * **Allowed Web Origins**: `http://localhost:5000`
        6. **Save Changes** をクリックします
        7. `.env` の `YOUR_AUTH0_DOMAIN` を、**Settings** タブにある **ドメイン** (例: `your-tenant.auth0.com`) に置き換えます
        8. `.env` の `YOUR_CLIENT_ID` を **クライアントID** に置き換えます
        9. `.env` の `YOUR_CLIENT_SECRET` を **クライアントシークレット** に置き換えます

        `AUTH0_SECRET` 用の安全なシークレットを生成します。

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

        <Info>
          **重要:** `.env` ファイルは絶対にバージョン管理にコミットしないでください。`.gitignore` に追加してください。
        </Info>
      </Tab>
    </Tabs>
  </Step>

  <Step title="認証設定、ルート、テンプレートを作成する" stepNumber={4}>
    ファイルを作成する

    ```bash theme={null}
    mkdir templates static && touch app.py auth.py templates/index.html templates/profile.html static/style.css
    ```

    次のコードスニペットを追加します。

    <AuthCodeGroup>
      ```python auth.py expandable lines theme={null}
      import os
      from auth0_server_python.auth_server.server_client import ServerClient
      from dotenv import load_dotenv

      load_dotenv()

      # 開発用のシンプルなインメモリストレージ
      # 本番環境では、Redis、PostgreSQL、またはその他の永続ストレージを使用してください
      class MemoryStateStore:
          """In-memory state store for session data (development only)"""
          def __init__(self):
              self._data = {}
          
          async def get(self, key, options=None):
              return self._data.get(key)
          
          async def set(self, key, value, options=None):
              self._data[key] = value
          
          async def delete(self, key, options=None):
              self._data.pop(key, None)
          
          async def delete_by_logout_token(self, claims, options=None):
              # バックチャネルログアウトのサポート用
              pass

      class MemoryTransactionStore:
          """In-memory transaction store for OAuth flows (development only)"""
          def __init__(self):
              self._data = {}
          
          async def get(self, key, options=None):
              return self._data.get(key)
          
          async def set(self, key, value, options=None):
              self._data[key] = value
          
          async def delete(self, key, options=None):
              self._data.pop(key, None)

      # ストアの初期化
      state_store = MemoryStateStore()
      transaction_store = MemoryTransactionStore()

      # Auth0 ServerClientの初期化
      auth0 = ServerClient(
          domain=os.getenv('AUTH0_DOMAIN'),
          client_id=os.getenv('AUTH0_CLIENT_ID'),
          client_secret=os.getenv('AUTH0_CLIENT_SECRET'),
          secret=os.getenv('AUTH0_SECRET'),
          redirect_uri=os.getenv('AUTH0_REDIRECT_URI'),
          state_store=state_store,
          transaction_store=transaction_store,
          authorization_params={
              'scope': 'openid profile email',
              'audience': os.getenv('AUTH0_AUDIENCE', '')  # 任意: APIアクセス用
          }
      )
      ```

      ```python app.py expandable lines theme={null}
      import os
      from flask import Flask, redirect, render_template, request, url_for, g
      from auth0_server_python.auth_types import LogoutOptions
      from auth import auth0
      from dotenv import load_dotenv

      load_dotenv()

      app = Flask(__name__)
      app.secret_key = os.getenv('AUTH0_SECRET')

      # Auth0のセッションを設定する
      app.config.update(
          SESSION_COOKIE_SECURE=False,  # 本番環境でHTTPSを使用する場合はTrueに設定する
          SESSION_COOKIE_HTTPONLY=True,
          SESSION_COOKIE_SAMESITE='Lax',
      )

      @app.before_request
      def store_request_response():
          """Make request/response available for Auth0 SDK"""
          g.store_options = {"request": request}

      @app.route('/')
      async def index():
          """Home page - shows login button or user profile"""
          user = await auth0.get_user(g.store_options)
          return render_template('index.html', user=user)

      @app.route('/login')
      async def login():
          """Redirect to Auth0 login"""
          authorization_url = await auth0.start_interactive_login({}, g.store_options)
          return redirect(authorization_url)

      @app.route('/callback')
      async def callback():
          """Handle Auth0 callback after login"""
          try:
              result = await auth0.complete_interactive_login(str(request.url), g.store_options)
              return redirect(url_for('index'))
          except Exception as e:
              return f"Authentication error: {str(e)}", 400

      @app.route('/profile')
      async def profile():
          """Protected route - shows user profile"""
          user = await auth0.get_user(g.store_options)
          
          if not user:
              return redirect(url_for('login'))
          
          return render_template('profile.html', user=user)

      @app.route('/logout')
      async def logout():
          """Logout and redirect to Auth0 logout"""
          options = LogoutOptions(return_to=url_for("index", _external=True))
          logout_url = await auth0.logout(options, g.store_options)
          return redirect(logout_url)

      if __name__ == '__main__':
          app.run(debug=True, port=5000)
      ```

      ```html templates/index.html expandable lines theme={null}
      <!DOCTYPE html>
      <html lang="en">
      <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Flask + Auth0</title>
      <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
      </head>
      <body>
      <div class="container">
          <div class="card">
              <img src="https://cdn.auth0.com/quantum-assets/dist/latest/logos/auth0/auth0-lockup-en-ondark.png"
                   alt="Auth0 Logo" class="logo">
              <h1>Flask + Auth0</h1>
              
              {% if user %}
                  <div class="logged-in">
                      <p class="success">✅ Successfully logged in!</p>
                      <div class="user-info">
                          {% if user.picture %}
                          <img src="{{ user.picture }}" alt="Profile" class="profile-pic">
                          {% endif %}
                          <h2>{{ user.name }}</h2>
                          <p>{{ user.email }}</p>
                      </div>
                      <a href="/profile" class="button">View Full Profile</a>
                      <a href="/logout" class="button logout">Log Out</a>
                  </div>
              {% else %}
                  <div class="logged-out">
                      <p>Welcome! Please log in to access your protected content.</p>
                      <a href="/login" class="button">Log In</a>
                  </div>
              {% endif %}
          </div>
      </div>
      </body>
      </html>
      ```

      ```html templates/profile.html expandable lines theme={null}
      <!DOCTYPE html>
      <html lang="en">
      <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>User Profile - Flask + Auth0</title>
      <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
      </head>
      <body>
      <div class="container">
          <div class="card">
              <img src="https://cdn.auth0.com/quantum-assets/dist/latest/logos/auth0/auth0-lockup-en-ondark.png"
                   alt="Auth0 Logo" class="logo">
              <h1>User Profile</h1>
              
              <div class="profile-details">
                  {% if user.picture %}
                  <img src="{{ user.picture }}" alt="Profile" class="profile-pic-large">
                  {% endif %}
                  
                  <div class="profile-info">
                      <h2>{{ user.name }}</h2>
                      <p class="email">{{ user.email }}</p>
                      
                      <div class="profile-data">
                          <h3>Profile Information</h3>
                          <dl>
                              <dt>User ID:</dt>
                              <dd>{{ user.sub }}</dd>
                              
                              {% if user.nickname %}
                              <dt>Nickname:</dt>
                              <dd>{{ user.nickname }}</dd>
                              {% endif %}
                              
                              {% if user.updated_at %}
                              <dt>Last Updated:</dt>
                              <dd>{{ user.updated_at }}</dd>
                              {% endif %}
                          </dl>
                      </div>
                  </div>
              </div>
              
              <div class="actions">
                  <a href="/" class="button">Back to Home</a>
                  <a href="/logout" class="button logout">Log Out</a>
              </div>
          </div>
      </div>
      </body>
      </html>
      ```

      ```css static/style.css expandable lines theme={null}
      @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');

      * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
      }

      body {
      font-family: 'Inter', sans-serif;
      background: linear-gradient(135deg, #1a1e27 0%, #2d313c 100%);
      min-height: 100vh;
      display: flex;
      justify-content: center;
      align-items: center;
      color: #e2e8f0;
      padding: 20px;
      }

      .container {
      width: 100%;
      max-width: 600px;
      }

      .card {
      background-color: #262a33;
      border-radius: 20px;
      box-shadow: 0 20px 60px rgba(0, 0, 0, 0.6), 0 0 0 1px rgba(255, 255, 255, 0.05);
      padding: 3rem;
      animation: fadeInScale 0.6s ease-out;
      }

      @keyframes fadeInScale {
      from {
          opacity: 0;
          transform: scale(0.95);
      }
      to {
          opacity: 1;
          transform: scale(1);
      }
      }

      .logo {
      width: 160px;
      margin: 0 auto 2rem;
      display: block;
      animation: slideDown 0.8s ease-out;
      }

      @keyframes slideDown {
      from {
          opacity: 0;
          transform: translateY(-30px);
      }
      to {
          opacity: 1;
          transform: translateY(0);
      }
      }

      h1 {
      font-size: 2.5rem;
      font-weight: 700;
      text-align: center;
      margin-bottom: 2rem;
      color: #f7fafc;
      text-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
      }

      h2 {
      font-size: 1.8rem;
      font-weight: 600;
      margin: 0.5rem 0;
      color: #f7fafc;
      }

      h3 {
      font-size: 1.3rem;
      font-weight: 600;
      margin-top: 1.5rem;
      margin-bottom: 1rem;
      color: #cbd5e0;
      }

      .logged-in, .logged-out {
      text-align: center;
      }

      .logged-out p {
      font-size: 1.2rem;
      color: #cbd5e0;
      margin-bottom: 2rem;
      line-height: 1.6;
      }

      .success {
      font-size: 1.5rem;
      color: #68d391;
      font-weight: 600;
      margin-bottom: 1.5rem;
      }

      .user-info {
      background-color: #2d313c;
      border-radius: 15px;
      padding: 2rem;
      margin: 2rem 0;
      }

      .profile-pic {
      width: 80px;
      height: 80px;
      border-radius: 50%;
      margin-bottom: 1rem;
      border: 3px solid #63b3ed;
      object-fit: cover;
      }

      .profile-pic-large {
      width: 120px;
      height: 120px;
      border-radius: 50%;
      margin-bottom: 1rem;
      border: 4px solid #63b3ed;
      object-fit: cover;
      }

      .user-info p, .email {
      color: #a0aec0;
      font-size: 1.1rem;
      }

      .button {
      display: inline-block;
      padding: 1rem 2.5rem;
      font-size: 1.1rem;
      font-weight: 600;
      border-radius: 10px;
      border: none;
      cursor: pointer;
      transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
      text-decoration: none;
      text-transform: uppercase;
      letter-spacing: 0.08em;
      margin: 0.5rem;
      background-color: #63b3ed;
      color: #1a1e27;
      box-shadow: 0 8px 20px rgba(0, 0, 0, 0.4);
      }

      .button:hover {
      background-color: #4299e1;
      transform: translateY(-3px);
      box-shadow: 0 12px 25px rgba(0, 0, 0, 0.5);
      }

      .button.logout {
      background-color: #fc8181;
      }

      .button.logout:hover {
      background-color: #e53e3e;
      }

      .profile-details {
      text-align: center;
      }

      .profile-info {
      background-color: #2d313c;
      border-radius: 15px;
      padding: 2rem;
      margin-top: 1.5rem;
      }

      .profile-data {
      margin-top: 2rem;
      text-align: left;
      }

      .profile-data dl {
      display: grid;
      grid-template-columns: 150px 1fr;
      gap: 1rem;
      margin-top: 1rem;
      }

      .profile-data dt {
      font-weight: 600;
      color: #cbd5e0;
      }

      .profile-data dd {
      color: #a0aec0;
      word-break: break-all;
      }

      .actions {
      margin-top: 2rem;
      display: flex;
      justify-content: center;
      flex-wrap: wrap;
      }

      @media (max-width: 600px) {
      .card {
          padding: 2rem;
      }

      h1 {
          font-size: 2rem;
      }

      .button {
          padding: 0.8rem 2rem;
          font-size: 1rem;
      }

      .logo {
          width: 120px;
      }

      .profile-data dl {
          grid-template-columns: 1fr;
          gap: 0.5rem;
      }

      .profile-data dt {
          margin-top: 1rem;
      }
      }
      ```
    </AuthCodeGroup>

    <Info>
      **開発時のみ:** この例では、説明のためにシンプルなインメモリストレージクラス (`MemoryStateStore` と `MemoryTransactionStore`) を使用しています。これらのストアは、アプリケーションを再起動するとすべてのセッションデータが失われ、マルチインスタンス構成のデプロイでは動作しません。

      **本番環境のアプリケーションでは**、永続ストレージを実装する必要があります。この SDK はフレームワークに依存しないため、独自の `StateStore` と `TransactionStore` の実装を提供する必要があります。Redis、PostgreSQL、その他の永続ストレージバックエンドの実装方法について詳しくは、[公式 SDK のストレージ実装例](https://github.com/auth0/auth0-server-python/blob/main/examples/ConfigureStore.md) を参照してください。
    </Info>
  </Step>

  <Step title="アプリを実行する" stepNumber={5}>
    Flask の開発サーバーを起動します。

    ```bash theme={null}
    python app.py
    ```

    アプリは [http://localhost:5000](http://localhost:5000) で利用できるようになります。Auth0 SDK は認証用のルートを自動的に処理します。
  </Step>
</Steps>

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

  これで、[localhost](http://localhost:5000/) で動作する Auth0 のログインページが完成しているはずです
</Check>

***

<div id="advanced-usage">
  ## 高度な使用方法
</div>

<Accordion title="APIトークンの取得">
  保護された API を呼び出す必要がある場合は、アクセストークンを取得します。

  ```python theme={null}
  @app.route('/api-call')
  @require_auth
  async def api_call():
      try:
          # API 用のアクセストークンを取得
          access_token = await auth0.get_access_token(
              audience='https://your-api.example.com',
              store_options=g.store_options
          )
          
          # トークンを使用して API を呼び出す
          # headers = {'Authorization': f'Bearer {access_token}'}
          # response = requests.get('https://your-api.example.com/data', headers=headers)
          
          return f"Access token retrieved: {access_token[:20]}..."
      except Exception as e:
          return f"Error getting access token: {str(e)}", 500
  ```

  <Info>
    この機能を使用するには、次の設定が必要です。

    1. `.env` ファイルで `AUTH0_AUDIENCE` を設定する
    2. スコープに `offline_access` を含める (リフレッシュトークン用)
    3. `auth.py` の `authorization_params` を更新する:
       ```python theme={null}
       authorization_params={
           'scope': 'openid profile email offline_access',
           'audience': os.getenv('AUTH0_AUDIENCE')
       }
       ```
  </Info>
</Accordion>

<Accordion title="カスタムストレージの設定">
  デフォルトでは、SDK は cookie ベースのストレージを使用します。特定の要件がある本番環境 (水平スケーリング、サービス間でのセッション共有など) では、Redis や PostgreSQL などのカスタムストレージバックエンドを設定できます。

  **カスタムストレージを使用するタイミング:**

  * 複数のサーバー間でセッションを共有する必要がある
  * cookie のサイズ制限を超える大きなセッションデータがある
  * バックチャネルログアウト向けに一元的なセッション管理が必要である

  **Redis の例:**

  ```python auth.py theme={null}
  from auth0_server_python.stores.redis_state_store import RedisStateStore
  import redis.asyncio as redis

  # カスタム状態ストアを初期化
  redis_client = redis.from_url(os.getenv('REDIS_URL', 'redis://localhost:6379'))
  state_store = RedisStateStore(
      secret=os.getenv('AUTH0_SECRET'),
      redis_client=redis_client
  )

  # ServerClient に渡す
  auth0 = ServerClient(
      domain=os.getenv('AUTH0_DOMAIN'),
      client_id=os.getenv('AUTH0_CLIENT_ID'),
      client_secret=os.getenv('AUTH0_CLIENT_SECRET'),
      secret=os.getenv('AUTH0_SECRET'),
      redirect_uri=os.getenv('AUTH0_REDIRECT_URI'),
      state_store=state_store,  # カスタムストレージ
      authorization_params={'scope': 'openid profile email'}
  )
  ```

  <Info>
    ほとんどのアプリケーションでは、デフォルトの cookie ベースのストレージで十分です。カスタムストレージを使用するには、`StateStore` インターフェイスを実装する必要があります。実装の詳細については、[SDK の例](https://github.com/auth0/auth0-server-python/blob/main/examples/ConfigureStore.md)を参照してください。
  </Info>
</Accordion>

***

<div id="common-issues">
  ## よくある問題
</div>

<AccordionGroup>
  <Accordion title="MissingRequiredArgumentError">
    **問題:** アプリの起動時に "MissingRequiredArgumentError: secret" が表示される

    **原因:** `AUTH0_SECRET` 環境変数が存在しないか、正しく読み込まれていません。

    **解決方法:**

    1. `.env` ファイルがプロジェクトのルートにあることを確認します
    2. `python-dotenv` がインストールされていることを確認します: `pip install python-dotenv`
    3. 必要に応じて新しいシークレットを生成します: `openssl rand -hex 64`
    4. 生成した値を `.env` に追加します: `AUTH0_SECRET=your_generated_secret`
    5. Flask アプリケーションを再起動します
  </Accordion>

  <Accordion title="無効なコールバックURLエラー">
    **問題:** ログイン時に "Callback URL mismatch" または "invalid\_request" エラーが表示される

    **原因:** コード内のリダイレクト URI が、Auth0 Dashboard に登録されているものと一致していません。

    **解決方法:**

    1. `.env` ファイルを確認します: `AUTH0_REDIRECT_URI=http://localhost:5000/callback`
    2. [Auth0 Dashboard](https://manage.auth0.com/dashboard/) → Applications → Your App → Settings に移動します
    3. `http://localhost:5000/callback` を **Allowed Callback URLs** に追加します
    4. **Save Changes** をクリックします
    5. Flask アプリケーションを再起動します
  </Accordion>

  <Accordion title="AsyncIO イベントループのエラー">
    **問題:** "RuntimeError: This event loop is already running" または同様の非同期関連のエラーが表示される

    **原因:** Flask 2.0 以降の非同期サポートでは、特定の構成で問題が発生することがあります。

    **解決策:**

    非同期サポートを有効にして Flask をインストールします。

    ```bash theme={null}
    pip install "flask[async]"
    ```

    次に、Flask アプリケーションを再起動します。
  </Accordion>

  <Accordion title="モジュールが見つからないエラー">
    **問題:** "ModuleNotFoundError: No module named 'auth0\_server\_python'" または同様のエラーが表示される

    **原因:** SDK がインストールされていないか、仮想環境が有効になっていません。

    **解決策:**

    1. 仮想環境が有効になっていることを確認します。
       ```bash theme={null}
       source venv/bin/activate  # macOS/Linux
       # または
       venv\Scripts\activate  # Windows
       ```
    2. SDK をインストールします。
       ```bash theme={null}
       pip install auth0-server-python "flask[async]" python-dotenv
       ```
    3. インストールを確認します。

    ```bash theme={null}
    pip list | grep auth0
    ```
  </Accordion>

  <Accordion title="ClaimDecodingFailed エラー">
    **問題:** 認証中に "ClaimDecodingFailed" または "Failed to decode claims" エラーが表示される

    **原因:** Auth0 から受け取った IDトークン または アクセストークン を正しくデコードできませんでした。多くの場合、原因は次のとおりです。

    * 無効な JWT 形式
    * 破損したセッションデータ
    * 署名アルゴリズムの不一致
    * サーバーと Auth0 間のクロックスキュー

    **解決策:**

    1. `.env` ファイル内の `AUTH0_CLIENT_SECRET` が正しいことを確認します
    2. システム時刻が同期されていることを確認します (NTP):
       ```bash theme={null}
       # macOS
       sudo sntp -sS time.apple.com

       # Linux
       sudo ntpdate -s time.nist.gov
       ```
    3. ブラウザーのクッキーを削除し、認証をやり直します
    4. `AUTH0_DOMAIN` に `https://` プレフィックスが含まれていないことを確認します
    5. Auth0 Dashboard → Applications → Your App → Settings → Advanced → OAuth → JsonWebToken Signature Algorithm が SDK の設定と一致していることを確認します
  </Accordion>

  <Accordion title="トークンの期限切れまたは無効">
    **問題:** "Token has expired" または "invalid\_token" エラーが表示される

    **原因:** アクセストークンまたはIDトークンの有効期間を超過しているか、セッションの有効期限が切れています。

    **解決策:**

    1. `offline_access` スコープを含めると、SDK が自動的にトークンの更新を処理します。
       ```python theme={null}
       authorization_params={
           'scope': 'openid profile email offline_access',
       }
       ```
    2. API の場合は、新しいトークンをリクエストするようにしてください。
       ```python theme={null}
       access_token = await auth0.get_access_token(
           audience='https://your-api.example.com',
           force_refresh=True  # 必要に応じて強制的に更新
       )
       ```
    3. Auth0 Dashboard → Applications → Your App → Settings → Advanced → OAuth で、トークンの有効期間を調整します
    4. トークンの有効期限が切れた場合にユーザーをログイン画面へリダイレクトできるよう、適切なエラー処理を実装します
  </Accordion>

  <Accordion title="CORS とクロスオリジンエラー">
    **問題:** ブラウザのコンソールに CORS エラーまたは "Blocked by CORS policy" が表示される

    **原因:** アプリケーションのオリジンが Auth0 側で適切に設定されていません。

    **解決策:**

    1. Auth0 Dashboard → Applications → Your App → Settings で、オリジンを追加します。
       * **Allowed Web Origins**: `http://localhost:5000`
       * **Allowed Callback URLs**: `http://localhost:5000/callback`
       * **Allowed Logout URLs**: `http://localhost:5000`
    2. 本番環境では、本番用の URL も追加します。
       ```
       https://yourdomain.com
       https://yourdomain.com/callback
       ```
    3. フロントエンドの JavaScript から Auth0 API を呼び出す場合は、Flask アプリで CORS が適切に設定されていることを確認します。
       ```python theme={null}
       from flask_cors import CORS
       CORS(app, origins=['http://localhost:5000'])
       ```
  </Accordion>

  <Accordion title="レート制限の超過">
    **問題:** "Too many requests" または "Rate limit exceeded" エラーが表示される

    **原因:** アプリケーションが認証リクエストに対する Auth0 の rate limits を超過しています。

    **解決策:**

    1. Auth0 Dashboard → Monitoring → Logs で rate limit の詳細を確認します
    2. リトライに指数バックオフを実装します。
       ```python theme={null}
       import time
       from auth0_server_python.error import ApiError

       async def login_with_retry():
           max_retries = 3
           for attempt in range(max_retries):
               try:
                   return await auth0.start_interactive_login({}, g.store_options)
               except ApiError as e:
                   if e.status_code == 429 and attempt < max_retries - 1:
                       wait_time = 2 ** attempt
                       time.sleep(wait_time)
                   else:
                       raise
       ```
    3. Auth0 のサブスクリプションプランの制限を確認します
    4. 不要なトークンリクエストを減らせるよう、authentication flow を最適化します
    5. 新しいトークンを頻繁にリクエストするのではなく、適切にキャッシュします
  </Accordion>
</AccordionGroup>
