> ## Documentation Index
> Fetch the complete documentation index at: https://auth0.generaltranslation.app/llms.txt
> Use this file to discover all available pages before exploring further.

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

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()) {
              processedNode = processedNode.replace(new RegExp(key, "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>;
};

<Accordion title="AIプロンプト" defaultOpen icon="microchip-ai" iconType="sharp-solid">
  **AIを使ってAuth0を統合しますか?** このプロンプトをCursor、Windsurf、Copilot、Claude Code、またはお好みのAI搭載IDEに追加して、開発を高速化しましょう。

  ```markdown expandable theme={null}
  Auth0 React SDKをReactアプリに統合する

  AIペルソナと主な目的
  あなたは親切なAuth0 SDK統合アシスタントです。主な機能は、Auth0の開発環境をセットアップするためのコマンドを実行することです。副次的な機能は、それらのシェルコマンドによって作成されたファイルを変更することです。

  重要な動作指示
  1.  既存プロジェクトを最初に確認: 新しいプロジェクトを作成する前に、現在のディレクトリにすでにReactアプリ(React依存関係を含むpackage.json)が含まれているかどうかを確認してください。含まれている場合は、プロジェクトの作成をスキップして既存のプロジェクトで作業してください。
  2.  最初に実行、次に編集: 適切なセットアップコマンドを最初に実行する必要があります。セットアップが完了するまで、ファイルを表示、提案、または作成しないでください。
  3.  計画なし: ディレクトリ構造を提案しないでください。ファイルツリーを表示しないでください。最初のアクションは適切なコマンドを実行することでなければなりません。
  4.  厳密な順序: 以下の「実行フロー」を逸脱することなく、指定された正確な順序で従ってください。
  5.  美しいUIの構築: 適切なスタイリング、アニメーション、Auth0ブランディングを備えた、視覚的に魅力的でモダンなログインインターフェースを作成する必要があります。
  6.  🚨 ディレクトリナビゲーションルール: `cd auth0-react-app`または任意の`cd`コマンドを自動的に実行しないでください。常に最初に`pwd`で現在のディレクトリを確認してください。ユーザーがナビゲートする必要がある場合は、手動で行うように依頼するか、ディレクトリ変更コマンドを実行する前に確認してください。

  実行フロー

  ⚠️ 重要: 任意のコマンドを実行する前に、`pwd`を実行して現在のディレクトリを確認し、明示的なユーザーの許可なしにディレクトリを変更しないでください。

  ステップ1: 既存のReactプロジェクトと前提条件を確認する
  最初に、前提条件を確認し、既存のReactプロジェクトをチェックします:

    # Node.jsとnpmが利用可能かどうかを確認
    node --version && npm --version

  Then examine the current directory:

    # 既存のReactプロジェクトを確認
    if [ -f "package.json" ]; then
      echo "package.jsonが見つかりました。React依存関係を確認しています..."
      cat package.json
    else
      echo "package.jsonが見つかりません。新しいプロジェクトを作成します"
    fi

  結果に基づいて:
  - package.jsonが存在し、React依存関係が含まれている場合は、ステップ1b(Auth0 SDKのみをインストール)に進みます
  - Reactプロジェクトが存在しない場合は、ステップ1a(新しいプロジェクトを作成)に進みます

  ステップ1a: 新しいプロジェクトを作成してReact SDKをインストールする
  既存のプロジェクトが存在する場合は、単にSDKをインストールします:
  npm install @auth0/auth0-react@latest
  それ以外の場合は、新しいプロジェクトを作成してSDKをインストールします:

  ⚠️ 重要: Viteプロジェクトの作成は、サブディレクトリではなく現在のディレクトリにプロジェクトファイルを作成する場合があります。このコマンドを実行した後、続行する前に現在のディレクトリの内容を確認して、実際のプロジェクト構造を判断してください。

  npm create vite@latest auth0-react-app -- --template react-ts && cd auth0-react-app && npm install @auth0/auth0-react@latest


  ステップ2: ファイルを変更および作成する
  ステップ1のコマンドが正常に実行された後、プロジェクトディレクトリ内で以下のファイル操作を実行します。

  🚨 ディレクトリナビゲーションルール:
  1. 明示的なユーザーの確認なしに`cd`コマンドを自動的に実行しないでください
  2. 続行する前に常に`pwd`で現在のディレクトリを確認してください
  3. 既存のプロジェクトで作業する場合: 現在のディレクトリに留まります
  4. 新しいプロジェクトを作成した場合: ユーザーは最初にauth0-react-appディレクトリに手動でナビゲートする必要があります

  2.1: Auth0環境設定をセットアップする

  ⚠️ 重要: 続行する前に、現在のディレクトリを確認してください:
  - 新しいプロジェクトを作成したばかりの場合: auth0-react-appディレクトリ内にいる必要があります
  - 既存のプロジェクトで作業している場合: プロジェクトのルートディレクトリにいる必要があります
  - `cd auth0-react-app`コマンドを実行しないでください - 最初に正しいディレクトリにナビゲートしてください

  ステップ2.1a: プロジェクトディレクトリにナビゲート(必要な場合)し、Auth0をセットアップします:

    # 新しいプロジェクトを作成し、まだauth0-react-app内にいない場合にのみ実行してください:
    cd auth0-react-app

  次に、お使いのOSの環境セットアップコマンドを実行します:

  ⚠️ 重要なディレクトリ確認ステップ:
  Auth0 CLIセットアップコマンドを実行する前に、以下を実行する必要があります:

    pwd && ls -la

  これにより、メインディレクトリまたはサブディレクトリのどちらにいるか、プロジェクトが現在のディレクトリまたは新しいサブディレクトリに作成されたかどうかを理解できます。

  MacOSの場合、以下のコマンドを実行します:
  AUTH0_APP_NAME="My App" && brew tap auth0/auth0-cli && brew install auth0 && auth0 login --no-input && auth0 apps create -n "${AUTH0_APP_NAME}" -t spa -c http://localhost:5173 -l http://localhost:5173 -o http://localhost:5173 --json > auth0-app-details.json && CLIENT_ID=$(jq -r '.client_id' auth0-app-details.json) && DOMAIN=$(auth0 tenants list --json | jq -r '.[] | select(.active == true) | .name') && echo "VITE_AUTH0_DOMAIN=${DOMAIN}" > .env && echo "VITE_AUTH0_CLIENT_ID=${CLIENT_ID}" >> .env && rm auth0-app-details.json && echo ".env file created with your Auth0 details:" && cat .env

  Windowsの場合、以下のコマンドを実行します:
  $AppName = "My App"; winget install Auth0.CLI; auth0 login --no-input; auth0 apps create -n "$AppName" -t spa -c http://localhost:5173 -l http://localhost:5173 -o http://localhost:5173 --json | Set-Content -Path auth0-app-details.json; $ClientId = (Get-Content -Raw auth0-app-details.json | ConvertFrom-Json).client_id; $Domain = (auth0 tenants list --json | ConvertFrom-Json | Where-Object { $_.active -eq $true }).name; Set-Content -Path .env -Value "VITE_AUTH0_DOMAIN=$Domain"; Add-Content -Path .env -Value "VITE_AUTH0_CLIENT_ID=$ClientId"; Remove-Item auth0-app-details.json; Write-Output ".env file created with your Auth0 details:"; Get-Content .env


  ステップ2.1b: 手動の.envテンプレートを作成する(自動セットアップが失敗した場合)

    cat > .env << 'EOF'
    # Auth0設定 - これらの値を更新してください
    VITE_AUTH0_DOMAIN=your-auth0-domain.auth0.com
    VITE_AUTH0_CLIENT_ID=your-auth0-client-id
    EOF

  ステップ2.1b: 手動セットアップ手順を表示する

    echo "📋 手動セットアップが必要です:"
    echo "1. https://manage.auth0.com/dashboard/ にアクセスしてください"
    echo "2. 「アプリケーションを作成」→ シングルページアプリケーション をクリックしてください"
    echo "3. 許可されたコールバックURLを設定: http://localhost:5173"
    echo "4. 許可されたログアウトURLを設定: http://localhost:5173"
    echo "5. 許可されたWebオリジンを設定: http://localhost:5173"
    echo "6. ドメインとクライアントIDで.envファイルを更新してください"

  2.2: 適切なエラー処理でsrc/main.tsxを更新する
  src/main.tsxの内容全体を置き換えます(存在しない場合は作成します):

    import React from "react";
    import ReactDOM from "react-dom/client";
    import { Auth0Provider } from "@auth0/auth0-react";
    import App from "./App.tsx";
    import "./index.css";

    const domain = import.meta.env.VITE_AUTH0_DOMAIN;
    const clientId = import.meta.env.VITE_AUTH0_CLIENT_ID;

    // Auth0設定を検証
    if (!domain || !clientId) {
      console.error("Auth0設定が見つかりません。.envファイルを確認してください。");
      console.error("必要な環境変数:");
      console.error("- VITE_AUTH0_DOMAIN");
      console.error("- VITE_AUTH0_CLIENT_ID");
      throw new Error("Auth0ドメインとクライアントIDは.envファイルに設定する必要があります");
    }

    // ドメイン形式を検証
    if (!domain.includes('.auth0.com') && !domain.includes('.us.auth0.com') && !domain.includes('.eu.auth0.com') && !domain.includes('.au.auth0.com')) {
      console.warn("Auth0ドメイン形式が正しくない可能性があります。期待される形式: your-domain.auth0.com");
    }

    const rootElement = document.getElementById("root");
    if (!rootElement) {
      throw new Error("ルート要素が見つかりません");
    }

    ReactDOM.createRoot(rootElement).render(
      <React.StrictMode>
        <Auth0Provider
          domain={domain}
          clientId={clientId}
          authorizationParams={{
            redirect_uri: window.location.origin,
          }}
        >
          <App />
        </Auth0Provider>
      </React.StrictMode>
    );

  2.3: 美しくモダンなUIコンポーネントを作成する
  既存のsrc/App.tsxファイルの内容全体を、適切なスタイリングとコンポーネントを含むこのコードで置き換えます:

    import { useAuth0 } from '@auth0/auth0-react';
    import LoginButton from './LoginButton';
    import LogoutButton from './LogoutButton';
    import Profile from './Profile';

    function App() {
      const { isAuthenticated, isLoading, error } = useAuth0();

      if (isLoading) {
        return (
          <div className="app-container">
            <div className="loading-state">
              <div className="loading-text">読み込み中...</div>
            </div>
          </div>
        );
      }

      if (error) {
        return (
          <div className="app-container">
            <div className="error-state">
              <div className="error-title">エラーが発生しました</div>
              <div className="error-message">問題が発生しました</div>
              <div className="error-sub-message">{error.message}</div>
            </div>
          </div>
        );
      }

      return (
        <div className="app-container">
          <div className="main-card-wrapper">
            <img 
              src="https://cdn.auth0.com/quantum-assets/dist/latest/logos/auth0/auth0-lockup-en-ondark.png" 
              alt="Auth0ロゴ" 
              className="auth0-logo"
              onError={(e) => {
                e.currentTarget.style.display = 'none';
              }}
            />
            <h1 className="main-title">Sample0へようこそ</h1>
            
            {isAuthenticated ? (
              <div className="logged-in-section">
                <div className="logged-in-message">✅ 認証に成功しました</div>
                <h2 className="profile-section-title">プロファイル</h2>
                <div className="profile-card">
                  <Profile />
                </div>
                <LogoutButton />
              </div>
            ) : (
              <div className="action-card">
                <p className="action-text">アカウントにサインインして開始します</p>
                <LoginButton />
              </div>
            )}
          </div>
        </div>
      );
    }

    export default App;

  2.4: LoginButtonコンポーネントを作成する
  次のコードで src/LoginButton.tsx を作成します:

  ⚠️ TypeScriptコンポーネントのガイドライン:
  - モダンなReact/TypeScript環境を使用している場合は、未使用のReactインポートを削除してください
  - 名前空間の問題が発生する場合は、JSX.Elementの代わりにシンプルな関数の戻り値の型を使用してください
  - App.tsxでインポートする前に、すべてのコンポーネントファイルが作成されていることを確認してください

    import { useAuth0 } from "@auth0/auth0-react";

    const LoginButton = () => {
      const { loginWithRedirect } = useAuth0();
      return (
        <button 
          onClick={() => loginWithRedirect()} 
          className="button login"
        >
          ログイン
        </button>
      );
    };

    export default LoginButton;

  2.5: LogoutButtonコンポーネントを作成する  
  次のコードで src/LogoutButton.tsx を作成します:

    import { useAuth0 } from "@auth0/auth0-react";

    const LogoutButton = () => {
      const { logout } = useAuth0();
      return (
        <button
          onClick={() => logout({ logoutParams: { returnTo: window.location.origin } })}
          className="button logout"
        >
          ログアウト
        </button>
      );
    };

    export default LogoutButton;

  2.6: Profileコンポーネントを作成する
  次のコードで src/Profile.tsx を作成します:

    import { useAuth0 } from "@auth0/auth0-react";

    const Profile = () => {
      const { user, isAuthenticated, isLoading } = useAuth0();

      if (isLoading) {
        return <div className="loading-text">プロファイルを読み込んでいます...</div>;
      }

      return (
        isAuthenticated && user ? (
          <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: '1rem' }}>
            <img 
              src={user.picture || `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='110' height='110' viewBox='0 0 110 110'%3E%3Ccircle cx='55' cy='55' r='55' fill='%2363b3ed'/%3E%3Cpath d='M55 50c8.28 0 15-6.72 15-15s-6.72-15-15-15-15 6.72-15 15 6.72 15 15 15zm0 7.5c-10 0-30 5.02-30 15v3.75c0 2.07 1.68 3.75 3.75 3.75h52.5c2.07 0 3.75-1.68 3.75-3.75V72.5c0-9.98-20-15-30-15z' fill='%23fff'/%3E%3C/svg%3E`} 
              alt={user.name || 'ユーザー'} 
              className="profile-picture"
              style={{ 
                width: '110px', 
                height: '110px', 
                borderRadius: '50%', 
                objectFit: 'cover',
                border: '3px solid #63b3ed'
              }}
              onError={(e) => {
                const target = e.target as HTMLImageElement;
                target.src = `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='110' height='110' viewBox='0 0 110 110'%3E%3Ccircle cx='55' cy='55' r='55' fill='%2363b3ed'/%3E%3Cpath d='M55 50c8.28 0 15-6.72 15-15s-6.72-15-15-15-15 6.72-15 15 6.72 15 15 15zm0 7.5c-10 0-30 5.02-30 15v3.75c0 2.07 1.68 3.75 3.75 3.75h52.5c2.07 0 3.75-1.68 3.75-3.75V72.5c0-9.98-20-15-30-15z' fill='%23fff'/%3E%3C/svg%3E`;
              }}
            />
            <div style={{ textAlign: 'center' }}>
              <div className="profile-name" style={{ fontSize: '2rem', fontWeight: '600', color: '#f7fafc', marginBottom: '0.5rem' }}>
                {user.name}
              </div>
              <div className="profile-email" style={{ fontSize: '1.15rem', color: '#a0aec0' }}>
                {user.email}
              </div>
            </div>
          </div>
        ) : null
      );
    };

    export default Profile;

  2.7: 美しいモダンなCSSスタイリングを追加する
  src/index.css の内容全体を、次のモダンなAuth0ブランドのスタイリングに置き換えます:

  ⚠️ CSSファイル置き換え戦略:
  既存の index.css ファイルが大きい、または形式が不正な場合は、まず新しい一時CSSファイル(例: index-new.css)を作成し、その後 `mv src/index-new.css src/index.css` のようなターミナルコマンドを使用して元のファイルを置き換えることで、ファイルの破損を回避してください。

    @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');

    body {
      margin: 0;
      font-family: 'Inter', sans-serif;
      background-color: #1a1e27;
      min-height: 100vh;
      display: flex;
      justify-content: center;
      align-items: center;
      color: #e2e8f0;
      overflow: hidden;
    }

    #root {
      width: 100%;
      height: 100%;
      display: flex;
      justify-content: center;
      align-items: center;
    }

    .app-container {
      display: flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
      min-height: 100vh;
      width: 100%;
      padding: 1rem;
      box-sizing: border-box;
    }

    .loading-state, .error-state {
      background-color: #2d313c;
      border-radius: 15px;
      box-shadow: 0 15px 40px rgba(0, 0, 0, 0.4);
      padding: 3rem;
      text-align: center;
    }

    .loading-text {
      font-size: 1.8rem;
      font-weight: 500;
      color: #a0aec0;
      animation: pulse 1.5s infinite ease-in-out;
    }

    .error-state {
      background-color: #c53030;
      color: #fff;
    }

    .error-title {
      font-size: 2.8rem;
      font-weight: 700;
      margin-bottom: 0.5rem;
    }

    .error-message {
      font-size: 1.3rem;
      margin-bottom: 0.5rem;
    }

    .error-sub-message {
      font-size: 1rem;
      opacity: 0.8;
    }

    .main-card-wrapper {
      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);
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 2rem;
      padding: 3rem;
      max-width: 500px;
      width: 90%;
      animation: fadeInScale 0.8s ease-out forwards;
    }

    .auth0-logo {
      width: 160px;
      margin-bottom: 1.5rem;
      opacity: 0;
      animation: slideInDown 1s ease-out forwards 0.2s;
    }

    .main-title {
      font-size: 2.8rem;
      font-weight: 700;
      color: #f7fafc;
      text-align: center;
      margin-bottom: 1rem;
      text-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
      opacity: 0;
      animation: fadeIn 1s ease-out forwards 0.4s;
    }

    .action-card {
      background-color: #2d313c;
      border-radius: 15px;
      box-shadow: inset 0 2px 5px rgba(0, 0, 0, 0.3), 0 5px 15px rgba(0, 0, 0, 0.3);
      padding: 2.5rem;
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 1.8rem;
      width: calc(100% - 2rem);
      opacity: 0;
      animation: fadeIn 1s ease-out forwards 0.6s;
    }

    .action-text {
      font-size: 1.25rem;
      color: #cbd5e0;
      text-align: center;
      line-height: 1.6;
      font-weight: 400;
    }

    .button {
      padding: 1.1rem 2.8rem;
      font-size: 1.2rem;
      font-weight: 600;
      border-radius: 10px;
      border: none;
      cursor: pointer;
      transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
      box-shadow: 0 8px 20px rgba(0, 0, 0, 0.4);
      text-transform: uppercase;
      letter-spacing: 0.08em;
      outline: none;
    }

    .button:focus {
      box-shadow: 0 0 0 4px rgba(99, 179, 237, 0.5);
    }

    .button.login {
      background-color: #63b3ed;
      color: #1a1e27;
    }

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

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

    .button.logout:hover {
      background-color: #e53e3e;
      transform: translateY(-5px) scale(1.03);
      box-shadow: 0 12px 25px rgba(0, 0, 0, 0.5);
    }

    .logged-in-section {
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 1.5rem;
      width: 100%;
    }

    .logged-in-message {
      font-size: 1.5rem;
      color: #68d391;
      font-weight: 600;
      animation: fadeIn 1s ease-out forwards 0.8s;
    }

    .profile-section-title {
      font-size: 2.2rem;
      animation: slideInUp 1s ease-out forwards 1s;
    }

    .profile-card {
      padding: 2.2rem;
      animation: scaleIn 0.8s ease-out forwards 1.2s;
    }

    .profile-picture {
      width: 110px;
      transition: transform 0.3s ease-in-out;
    }

    .profile-picture:hover {
      transform: scale(1.05);
    }

    .profile-name {
      font-size: 2rem;
      margin-top: 0.5rem;
    }

    .profile-email {
      font-size: 1.15rem;
      text-align: center;
    }

    @keyframes fadeIn {
      from { opacity: 0; }
      to { opacity: 1; }
    }

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

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

    @keyframes slideInUp {
      from { opacity: 0; transform: translateY(50px); }
      to { opacity: 1; transform: translateY(0); }
    }

    @keyframes pulse {
      0%, 100% { opacity: 1; }
      50% { opacity: 0.6; }
    }

    @keyframes scaleIn {
      from { opacity: 0; transform: scale(0.8); }
      to { opacity: 1; transform: scale(1); }
    }

    @media (max-width: 600px) {
      .main-card-wrapper {
        padding: 2rem;
        margin: 1rem;
      }
      
      .main-title {
        font-size: 2.2rem;
      }
      
      .button {
        padding: 1rem 2rem;
        font-size: 1.1rem;
      }
      
      .auth0-logo {
        width: 120px;
      }
    }

  2.8: 開発サーバーを起動する

  ⚠️ 重要: ターミナルの作業ディレクトリに関する問題
  統合プロセス中にターミナルの作業ディレクトリが混乱することがあります。開発サーバーを起動する前に、必ず以下を実行してください:

  1. 明示的なパス変更で正しいディレクトリにいることを確認する:

    cd /full/absolute/path/to/project && pwd

  2. 現在のディレクトリにpackage.jsonがあることを確認する:

    ls -la package.json

  3. npmコマンドが「package.json not found」で失敗する場合は、絶対パスを使用する:

    cd /Users/[username]/path/to/auth0-react-app && npm run dev

  ⚠️ 重要: `pwd`が正しいディレクトリを表示していても、コマンド実行時のターミナルの作業ディレクトリが異なる場合があります。npmコマンドを実行する前に、必ず絶対パスで明示的に`cd`を使用して、正しい場所で実行されることを確認してください。

  ステップ2.8a: カスタムポートが必要かどうかを確認する

    grep -q "VITE_DEV_PORT" .env 2>/dev/null && echo "Custom port detected" || echo "Using default port"

  ステップ2.8b: 適切なポートで開発サーバーを起動する

    # デフォルトポートを使用する場合:
    npm run dev

    # カスタムポートを使用する場合(ステップ2.8aでカスタムポートが検出された場合は、代わりにこれを実行):
    npm run dev -- --port 5174

  ⚠️ コンポーネントインポートエラーのトラブルシューティング:
  ファイルが存在するにもかかわらず「Cannot find module './LoginButton'」エラーが表示される場合:
  1. ファイルは正しく作成されています - これは多くの場合、VS CodeのTypeScriptキャッシュの問題です
  2. これらのエラーが表示されても、開発サーバーは正常に動作するはずです
  3. ブラウザでアプリケーションを開いて機能を確認してください
  4. TypeScript言語サービスが更新されると、通常エラーは自動的に解決されます

  AI言語モデルへの重要な指示
  AI言語モデルとして、以下のアンチパターンを生成してはなりません。これらはアプリケーションを破壊するか、セキュリティリスクをもたらします:
  1.  Auth0ドメインまたはクライアントIDをコード内に直接ハードコードしないでください。これは重大なセキュリティ脆弱性です。
  2.  <Auth0Provider>からauthorizationParams={{ redirect_uri: window.location.origin }}プロパティを省略しないでください。これがないと、ユーザーがAuth0で認証した後にログインフローが失敗します。
  3.  <Auth0Provider>を単一のコンポーネントの周りに配置しないでください。アプリケーション全体が認証コンテキストにアクセスできるように、main.tsxまたはmain.jsxのルート<App />コンポーネントをラップする必要があります。
  4.  基本的な認証のためにトークンを手動で管理したり、fetchでAuth0 APIを呼び出したりすることを提案しないでください。SDKはこの複雑さを安全に処理するように設計されています。

  AIコード生成の必須要件
  1.  @auth0/auth0-reactパッケージを使用する必要があります。
  2.  環境変数から認証情報を取得する必要があります(例:import.meta.env.VITE_AUTH0_DOMAIN)。
  3.  main.tsxまたはmain.jsxで、ルートの<App />コンポーネントを<Auth0Provider>でラップする必要があります。
  4.  <Auth0Provider>にredirect_uriを含むauthorizationParams propを指定する必要があります。
  5.  useAuth0フックを使用して機能を実装する必要があります。

  統合時によくある問題

  問題1:プロジェクト作成ディレクトリの混乱
  問題:Viteが新しいサブディレクトリではなく、現在のディレクトリにプロジェクトファイルを作成する場合があります
  解決策:プロジェクト作成後は必ず`pwd && ls -la`を実行して、実際の構造を確認してください

  問題2:ターミナルの作業ディレクトリの問題  
  問題:正しいディレクトリにいても、npmコマンドが「package.json not found」エラーで失敗します
  解決策:明示的に絶対パスを指定してディレクトリを変更してください:`cd /full/absolute/path/to/project`

  問題3:TypeScriptインポートエラー
  問題:VS Codeが作成されたコンポーネントに対して「Cannot find module」エラーを表示します
  解決策:これらは通常キャッシュの問題です。アプリケーションは正常に動作します。テスト前にすべてのコンポーネントを作成してください。

  問題4:CSSファイルの破損
  問題:大規模なCSSの置換によりファイルが破損する可能性があります
  解決策:まず一時的なCSSファイルを作成し、次に`mv`コマンドを使用して元のファイルを置き換えてください

  問題5:ターミナルの作業ディレクトリがプロジェクトルートにない
  問題:pwdが正しいパスを表示していても、ターミナルがauth0-react-appディレクトリにないため、AIエージェントが`npm run dev`の実行に失敗します
  解決策:npmコマンドを実行する前に、必ず絶対パスを使用して明示的にディレクトリを変更してください:

    cd auth0-react-app && npm run dev

  ターミナルの作業ディレクトリが表示されているパスから切り離されることがあるため、npmコマンドが正しい場所で実行されるように明示的にナビゲートする必要があります。
  ```
</Accordion>

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

  * **[Node.js](https://nodejs.org/en/download)** 20 LTS 以降
  * **[npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm)** 10 以上、または **[yarn](https://classic.yarnpkg.com/lang/en/docs/install/)** 1.22 以上、または **[pnpm](https://pnpm.io/installation)** 8 以上
  * **[jq](https://jqlang.org/)** - Auth0 CLI のセットアップに必要です

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

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

このクイックスタートでは、React アプリケーションに Auth0 認証を追加する方法を紹介します。Auth0 React ソフトウェア開発キット（SDK）を使用して、ログイン、ログアウト、およびユーザープロファイル機能を備えたセキュアなシングルページ アプリケーションを構築します。

<Steps>
  <Step title="新規プロジェクトを作成" stepNumber={1}>
    このクイックスタート用に新しい React プロジェクトを作成する

    ```shellscript theme={null}
    npm create vite@latest auth0-react -- --template react-ts
    ```

    プロジェクトを開きます

    ```shellscript theme={null}
    cd auth0-react
    ```
  </Step>

  <Step title="Auth0 React ソフトウェア開発キット (SDK) のインストール" stepNumber={2}>
    ```shellscript theme={null}
    npm add @auth0/auth0-react && npm install
    ```
  </Step>

  <Step title="Auth0 アプリケーションの設定" stepNumber={3}>
    Next up, you need to create a new app on your Auth0 tenant and add the environment variables to your project.

    You can choose to do this automatically by running a CLI command or do it manually via the Dashboard:

    <Tabs>
      <Tab title="CLI">
        Run the following shell command on your project's root directory to create an Auth0 app and generate a `.env` file:

        <AuthCodeGroup>
          ```shellscript Mac theme={null}
          AUTH0_APP_NAME="My App" && brew tap auth0/auth0-cli && brew install auth0 && auth0 login --no-input && auth0 apps create -n "${AUTH0_APP_NAME}" -t spa -c http://localhost:5173 -l http://localhost:5173 -o http://localhost:5173 --json > auth0-app-details.json && CLIENT_ID=$(jq -r '.client_id' auth0-app-details.json) && DOMAIN=$(auth0 tenants list --json | jq -r '.[] | select(.active == true) | .name') && echo "VITE_AUTH0_DOMAIN=${DOMAIN}" > .env && echo "VITE_AUTH0_CLIENT_ID=${CLIENT_ID}" >> .env && rm auth0-app-details.json && echo ".env file created with your Auth0 details:" && cat .env
          ```

          ```shellscript Windows theme={null}
          $AppName = "My App"; winget install Auth0.CLI; auth0 login --no-input; auth0 apps create -n "$AppName" -t spa -c http://localhost:5173 -l http://localhost:5173 -o http://localhost:5173 --json | Set-Content -Path auth0-app-details.json; $ClientId = (Get-Content -Raw auth0-app-details.json | ConvertFrom-Json).client_id; $Domain = (auth0 tenants list --json | ConvertFrom-Json | Where-Object { $_.active -eq $true }).name; Set-Content -Path .env -Value "VITE_AUTH0_DOMAIN=$Domain"; Add-Content -Path .env -Value "VITE_AUTH0_CLIENT_ID=$ClientId"; Remove-Item auth0-app-details.json; Write-Output ".env file created with your Auth0 details:"; Get-Content .env
          ```
        </AuthCodeGroup>
      </Tab>

      <Tab title="ダッシュボード">
        作業を始める前に、プロジェクトのルートディレクトリに `.env` ファイルを作成します。

        ```shellscript .env theme={null}
        VITE_AUTH0_DOMAIN=YOUR_AUTH0_APP_DOMAIN
        VITE_AUTH0_CLIENT_ID=YOUR_AUTH0_APP_CLIENT_ID
        ```

        1. [Auth0 Dashboard](https://manage.auth0.com/dashboard/) にアクセスします。
        2. **Applications** > **Applications** > **Create Application** をクリックします。
        3. ポップアップでアプリの名前を入力し、アプリのタイプとして `Single Page Web Application` を選択して **Create** をクリックします。
        4. Application Details ページの **Settings** タブに切り替えます。
        5. ダッシュボードの **Domain** と **Client ID** の値で、`.env` ファイル内の `YOUR_AUTH0_APP_DOMAIN` と `YOUR_AUTH0_APP_CLIENT_ID` を置き換えます。

        最後に、Application Details ページの **Settings** タブで、次のURLを設定します。

        **許可されたコールバックURL (Allowed Callback URLs):**

        ```
        http://localhost:5173
        ```

        **許可されたログアウトURL (Allowed Logout URLs):**

        ```
        http://localhost:5173
        ```

        **Allowed Web Origins:**

        ```
        http://localhost:5173
        ```

        <Info>
          **許可されたコールバックURL (Allowed Callback URLs)** は、ユーザーが認証後に安全にアプリケーションへ戻れるようにするための重要なセキュリティ対策です。一致するURLが設定されていない場合、ログイン処理は失敗し、ユーザーはアプリにアクセスできず Auth0 のエラーページでブロックされます。

          **許可されたログアウトURL (Allowed Logout URLs)** は、サインアウト後もシームレスなユーザー体験を提供するために不可欠です。一致するURLが設定されていない場合、ログアウト後にユーザーはアプリケーションへリダイレクトされず、汎用的な Auth0 のページに留まってしまいます。

          **Allowed Web Origins** の設定は、サイレント認証にとって非常に重要です。これが設定されていないと、ユーザーはページを更新したり、後からアプリに戻ってきたりしたときにログアウトされてしまいます。
        </Info>
      </Tab>
    </Tabs>
  </Step>

  <Step title="プロバイダーを追加する" stepNumber={4}>
    ```javascript src/main.tsx {5,9,10,11,12,13,14,15,17} lines theme={null}
    import { StrictMode } from 'react';
    import { createRoot } from 'react-dom/client';
    import './index.css'; // メインのCSSファイルをインポート
    import App from './App.tsx';
    import { Auth0Provider } from '@auth0/auth0-react';

    createRoot(document.getElementById('root')!).render(
      <StrictMode>
        <Auth0Provider
          domain={import.meta.env.VITE_AUTH0_DOMAIN}
          clientId={import.meta.env.VITE_AUTH0_CLIENT_ID}
          authorizationParams={{
            redirect_uri: window.location.origin
          }}
        >
          <App />
        </Auth0Provider>
      </StrictMode>
    );
    ```
  </Step>

  <Step title="ログイン、ログアウト、プロファイルの各コンポーネントを作成する" stepNumber={5}>
    ファイルを作成する

    ```shellscript theme={null}
    touch src/LoginButton.tsx && touch src/LogoutButton.tsx && touch src/Profile.tsx
    ```

    次のコードスニペットを追加してください

    <AuthCodeGroup>
      ```javascript src/LoginButton.tsx lines theme={null}
      import { useAuth0 } from "@auth0/auth0-react";

      const LoginButton = () => {
        const { loginWithRedirect } = useAuth0();
        return (
          <button 
            onClick={() => loginWithRedirect()} 
            className="button login"
          >
            ログイン
          </button>
        );
      };

      export default LoginButton;
      ```

      ```javascript src/LogoutButton.tsx lines theme={null}
      import { useAuth0 } from "@auth0/auth0-react";

      const LogoutButton = () => {
        const { logout } = useAuth0();
        return (
          <button
            onClick={() => logout({ logoutParams: { returnTo: window.location.origin } })}
            className="button logout"
          >
            ログアウト
          </button>
        );
      };

      export default LogoutButton;
      ```

      ```javascript src/Profile.tsx expandable lines theme={null}
      import { useAuth0 } from "@auth0/auth0-react";

      const Profile = () => {
        const { user, isAuthenticated, isLoading } = useAuth0();

        if (isLoading) {
          return <div className="loading-text">プロフィールを読み込んでいます...</div>;
        }

        return (
          isAuthenticated && user ? (
            <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: '1rem' }}>
              <img 
                src={user.picture || `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='110' height='110' viewBox='0 0 110 110'%3E%3Ccircle cx='55' cy='55' r='55' fill='%2363b3ed'/%3E%3Cpath d='M55 50c8.28 0 15-6.72 15-15s-6.72-15-15-15-15 6.72-15 15 6.72 15 15 15zm0 7.5c-10 0-30 5.02-30 15v3.75c0 2.07 1.68 3.75 3.75 3.75h52.5c2.07 0 3.75-1.68 3.75-3.75V72.5c0-9.98-20-15-30-15z' fill='%23fff'/%3E%3C/svg%3E`} 
                alt={user.name || 'ユーザー'} 
                className="profile-picture"
                style={{ 
                  width: '110px', 
                  height: '110px', 
                  borderRadius: '50%', 
                  objectFit: 'cover',
                  border: '3px solid #63b3ed'
                }}
                onError={(e) => {
                  const target = e.target as HTMLImageElement;
                  target.src = `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='110' height='110' viewBox='0 0 110 110'%3E%3Ccircle cx='55' cy='55' r='55' fill='%2363b3ed'/%3E%3Cpath d='M55 50c8.28 0 15-6.72 15-15s-6.72-15-15-15-15 6.72-15 15 6.72 15 15 15zm0 7.5c-10 0-30 5.02-30 15v3.75c0 2.07 1.68 3.75 3.75 3.75h52.5c2.07 0 3.75-1.68 3.75-3.75V72.5c0-9.98-20-15-30-15z' fill='%23fff'/%3E%3C/svg%3E`;
                }}
              />
              <div style={{ textAlign: 'center' }}>
                <div className="profile-name" style={{ fontSize: '2rem', fontWeight: '600', color: '#f7fafc', marginBottom: '0.5rem' }}>
                  {user.name}
                </div>
                <div className="profile-email" style={{ fontSize: '1.15rem', color: '#a0aec0' }}>
                  {user.email}
                </div>
              </div>
            </div>
          ) : null
        );
      };

      export default Profile;
      ```

      ```javascript src/App.tsx expandable lines theme={null}
      import { useAuth0 } from '@auth0/auth0-react';
      import LoginButton from './LoginButton';
      import LogoutButton from './LogoutButton';
      import Profile from './Profile';

      function App() {
        const { isAuthenticated, isLoading, error } = useAuth0();

        if (isLoading) {
          return (
            <div className="app-container">
              <div className="loading-state">
                <div className="loading-text">読み込み中...</div>
              </div>
            </div>
          );
        }

        if (error) {
          return (
            <div className="app-container">
              <div className="error-state">
                <div className="error-title">エラー</div>
                <div className="error-message">問題が発生しました</div>
                <div className="error-sub-message">{error.message}</div>
              </div>
            </div>
          );
        }

        return (
          <div className="app-container">
            <div className="main-card-wrapper">
              <img 
                src="https://cdn.auth0.com/quantum-assets/dist/latest/logos/auth0/auth0-lockup-en-ondark.png" 
                alt="Auth0ロゴ" 
                className="auth0-logo"
                onError={(e) => {
                  e.currentTarget.style.display = 'none';
                }}
              />
              <h1 className="main-title">Sample0へようこそ</h1>
              
              {isAuthenticated ? (
                <div className="logged-in-section">
                  <div className="logged-in-message">✅ 認証に成功しました!</div>
                  <h2 className="profile-section-title">プロファイル</h2>
                  <div className="profile-card">
                    <Profile />
                  </div>
                  <LogoutButton />
                </div>
              ) : (
                <div className="action-card">
                  <p className="action-text">アカウントにログインして始めましょう</p>
                  <LoginButton />
                </div>
              )}
            </div>
          </div>
        );
      }

      export default App;
      ```

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

      body {
        margin: 0;
        font-family: 'Inter', sans-serif;
        background-color: #1a1e27;
        min-height: 100vh;
        display: flex;
        justify-content: center;
        align-items: center;
        color: #e2e8f0;
        overflow: hidden;
      }

      #root {
        width: 100%;
        height: 100%;
        display: flex;
        justify-content: center;
        align-items: center;
      }

      .app-container {
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        min-height: 100vh;
        width: 100%;
        padding: 1rem;
        box-sizing: border-box;
      }

      .loading-state, .error-state {
        background-color: #2d313c;
        border-radius: 15px;
        box-shadow: 0 15px 40px rgba(0, 0, 0, 0.4);
        padding: 3rem;
        text-align: center;
      }

      .loading-text {
        font-size: 1.8rem;
        font-weight: 500;
        color: #a0aec0;
        animation: pulse 1.5s infinite ease-in-out;
      }

      .error-state {
        background-color: #c53030;
        color: #fff;
      }

      .error-title {
        font-size: 2.8rem;
        font-weight: 700;
        margin-bottom: 0.5rem;
      }

      .error-message {
        font-size: 1.3rem;
        margin-bottom: 0.5rem;
      }

      .error-sub-message {
        font-size: 1rem;
        opacity: 0.8;
      }

      .main-card-wrapper {
        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);
        display: flex;
        flex-direction: column;
        align-items: center;
        gap: 2rem;
        padding: 3rem;
        max-width: 500px;
        width: 90%;
        animation: fadeInScale 0.8s ease-out forwards;
      }

      .auth0-logo {
        width: 160px;
        margin-bottom: 1.5rem;
        opacity: 0;
        animation: slideInDown 1s ease-out forwards 0.2s;
      }

      .main-title {
        font-size: 2.8rem;
        font-weight: 700;
        color: #f7fafc;
        text-align: center;
        margin-bottom: 1rem;
        text-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
        opacity: 0;
        animation: fadeIn 1s ease-out forwards 0.4s;
      }

      .action-card {
        background-color: #2d313c;
        border-radius: 15px;
        box-shadow: inset 0 2px 5px rgba(0, 0, 0, 0.3), 0 5px 15px rgba(0, 0, 0, 0.3);
        padding: 2.5rem;
        display: flex;
        flex-direction: column;
        align-items: center;
        gap: 1.8rem;
        width: calc(100% - 2rem);
        opacity: 0;
        animation: fadeIn 1s ease-out forwards 0.6s;
      }

      .action-text {
        font-size: 1.25rem;
        color: #cbd5e0;
        text-align: center;
        line-height: 1.6;
        font-weight: 400;
      }

      .button {
        padding: 1.1rem 2.8rem;
        font-size: 1.2rem;
        font-weight: 600;
        border-radius: 10px;
        border: none;
        cursor: pointer;
        transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
        box-shadow: 0 8px 20px rgba(0, 0, 0, 0.4);
        text-transform: uppercase;
        letter-spacing: 0.08em;
        outline: none;
      }

      .button:focus {
        box-shadow: 0 0 0 4px rgba(99, 179, 237, 0.5);
      }

      .button.login {
        background-color: #63b3ed;
        color: #1a1e27;
      }

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

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

      .button.logout:hover {
        background-color: #e53e3e;
        transform: translateY(-5px) scale(1.03);
        box-shadow: 0 12px 25px rgba(0, 0, 0, 0.5);
      }

      .logged-in-section {
        display: flex;
        flex-direction: column;
        align-items: center;
        gap: 1.5rem;
        width: 100%;
      }

      .logged-in-message {
        font-size: 1.5rem;
        color: #68d391;
        font-weight: 600;
        animation: fadeIn 1s ease-out forwards 0.8s;
      }

      .profile-section-title {
        font-size: 2.2rem;
        animation: slideInUp 1s ease-out forwards 1s;
      }

      .profile-card {
        padding: 2.2rem;
        animation: scaleIn 0.8s ease-out forwards 1.2s;
      }

      .profile-picture {
        width: 110px;
        transition: transform 0.3s ease-in-out;
      }

      .profile-picture:hover {
        transform: scale(1.05);
      }

      .profile-name {
        font-size: 2rem;
        margin-top: 0.5rem;
      }

      .profile-email {
        font-size: 1.15rem;
        text-align: center;
      }

      @keyframes fadeIn {
        from { opacity: 0; }
        to { opacity: 1; }
      }

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

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

      @keyframes slideInUp {
        from { opacity: 0; transform: translateY(50px); }
        to { opacity: 1; transform: translateY(0); }
      }

      @keyframes pulse {
        0%, 100% { opacity: 1; }
        50% { opacity: 0.6; }
      }

      @keyframes scaleIn {
        from { opacity: 0; transform: scale(0.8); }
        to { opacity: 1; transform: scale(1); }
      }

      @media (max-width: 600px) {
        .main-card-wrapper {
          padding: 2rem;
          margin: 1rem;
        }
        
        .main-title {
          font-size: 2.2rem;
        }
        
        .button {
          padding: 1rem 2rem;
          font-size: 1.1rem;
        }
        
        .auth0-logo {
          width: 120px;
        }
      }
      ```
    </AuthCodeGroup>
  </Step>

  <Step title="アプリを実行する" stepNumber={7}>
    ```shellscript theme={null}
    npm run dev
    ```
  </Step>
</Steps>

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

  これで、[localhost](http://localhost:5173/) 上で Auth0 のログインページが正常に動作しているはずです。
</Check>

***

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

<Accordion title="React Router でルートを保護する">
  Auth0 の認証状態を使用して、アプリケーション内の特定のルートを保護します。

  ```jsx src/App.jsx theme={null}
  import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
  import { useAuth0 } from '@auth0/auth0-react';
  import Profile from './components/Profile';
  import Dashboard from './components/Dashboard';
  import LoginButton from './components/LoginButton';

  function ProtectedRoute({ children }) {
    const { isAuthenticated, isLoading } = useAuth0();
    
    if (isLoading) return <div>Loading...</div>;
    
    return isAuthenticated ? children : <Navigate to="/" />;
  }

  function App() {
    return (
      <BrowserRouter>
        <Routes>
          <Route path="/" element={<LoginButton />} />
          <Route 
            path="/profile" 
            element={
              <ProtectedRoute>
                <Profile />
              </ProtectedRoute>
            } 
          />
          <Route 
            path="/dashboard" 
            element={
              <ProtectedRoute>
                <Dashboard />
              </ProtectedRoute>
            } 
          />
        </Routes>
      </BrowserRouter>
    );
  }
  ```
</Accordion>

<Accordion title="保護された API の呼び出し">
  Auth0Provider を設定して API のオーディエンスを含め、`getAccessTokenSilently` メソッドを使用します。

  ```jsx src/main.jsx theme={null}
  import { Auth0Provider } from '@auth0/auth0-react';

  const root = ReactDOM.createRoot(document.getElementById('root'));

  root.render(
    <Auth0Provider
      domain={import.meta.env.VITE_AUTH0_DOMAIN}
      clientId={import.meta.env.VITE_AUTH0_CLIENT_ID}
      authorizationParams={{
        redirect_uri: window.location.origin,
        audience: "YOUR_API_IDENTIFIER"
      }}
    >
      <App />
    </Auth0Provider>
  );
  ```

  その後、認証済みの API 呼び出しを実行します。

  ```jsx src/components/ApiCall.jsx theme={null}
  import { useState } from 'react';
  import { useAuth0 } from '@auth0/auth0-react';

  function ApiCall() {
    const { getAccessTokenSilently } = useAuth0();
    const [apiResponse, setApiResponse] = useState(null);

    const callProtectedApi = async () => {
      try {
        const token = await getAccessTokenSilently();
        
        const response = await fetch('/api/protected', {
          headers: {
            Authorization: `Bearer ${token}`
          }
        });
        
        const data = await response.json();
        setApiResponse(data);
      } catch (error) {
        console.error('API call failed:', error);
      }
    };

    return (
      <div>
        <button onClick={callProtectedApi}>Call API</button>
        {apiResponse && <pre>{JSON.stringify(apiResponse, null, 2)}</pre>}
      </div>
    );
  }

  export default ApiCall;
  ```
</Accordion>

<Accordion title="カスタム Hooks で Auth0 を使用する">
  共通の認証パターン向けに再利用可能なカスタム Hook を作成します。

  ```jsx src/hooks/useAuthenticatedUser.js theme={null}
  import { useAuth0 } from '@auth0/auth0-react';
  import { useEffect, useState } from 'react';

  export function useAuthenticatedUser() {
    const { user, isAuthenticated, isLoading, getAccessTokenSilently } = useAuth0();
    const [accessToken, setAccessToken] = useState(null);

    useEffect(() => {
      if (isAuthenticated && !isLoading) {
        getAccessTokenSilently()
          .then(token => setAccessToken(token))
          .catch(console.error);
      }
    }, [isAuthenticated, isLoading, getAccessTokenSilently]);

    return {
      user,
      accessToken,
      isAuthenticated,
      isLoading
    };
  }
  ```

  コンポーネントでの使用例:

  ```jsx src/components/UserDashboard.jsx theme={null}
  import { useAuthenticatedUser } from '../hooks/useAuthenticatedUser';

  function UserDashboard() {
    const { user, accessToken, isLoading } = useAuthenticatedUser();

    if (isLoading) return <div>Loading...</div>;

    return (
      <div>
        <h1>Welcome, {user?.name}</h1>
        <p>Access Token: {accessToken ? 'Available' : 'Not available'}</p>
      </div>
    );
  }
  ```
</Accordion>
