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

# TanStack Start アプリケーションにログインを追加する

> このガイドでは、Auth0 TanStack Start React SDK を使用して、TanStack Start React アプリケーションを Auth0 と連携する方法を説明します。

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("Error creating client:", 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={`マイ ${placeholderText} アプリ`} 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 />;
};

export const AuthCodeBlock = ({filename, icon, language, highlight, children}) => {
  const [displayText, setDisplayText] = useState(children);
  const [copyText, setCopyText] = useState(children);
  const wrapperRef = React.useRef(null);
  useEffect(() => {
    let unsubscribe = null;
    function init() {
      if (!window.autorun || !window.rootStore) {
        return;
      }
      unsubscribe = window.autorun(() => {
        let processedChildrenForDisplay = children;
        let processedChildrenForCopy = children;
        for (const [key, value] of window.rootStore.variableStore.values.entries()) {
          const escapedKey = key.replaceAll(/[.*+?^${}()|[\]\\]/g, (String.raw)`\$&`);
          let displayValue = value;
          if (key === "{yourClientSecret}" && value !== "{yourClientSecret}") {
            displayValue = value.substring(0, 3) + "*****MASKED*****";
          }
          processedChildrenForDisplay = processedChildrenForDisplay.replaceAll(new RegExp(escapedKey, "g"), displayValue);
          processedChildrenForCopy = processedChildrenForCopy.replaceAll(new RegExp(escapedKey, "g"), value);
        }
        setDisplayText(processedChildrenForDisplay);
        setCopyText(processedChildrenForCopy);
      });
    }
    if (window.rootStore) {
      init();
    } else {
      window.addEventListener("adu:storeReady", init);
    }
    return () => {
      window.removeEventListener("adu:storeReady", init);
      unsubscribe?.();
    };
  }, [children]);
  useEffect(() => {
    if (!wrapperRef.current) return;
    const originalWriteText = navigator.clipboard.writeText.bind(navigator.clipboard);
    let isOverriding = false;
    const handleClick = e => {
      const button = e.target.closest('[data-testid="copy-code-button"]');
      if (!button || !wrapperRef.current.contains(button)) return;
      isOverriding = true;
      navigator.clipboard.writeText = text => {
        if (isOverriding) {
          isOverriding = false;
          navigator.clipboard.writeText = originalWriteText;
          return originalWriteText(copyText);
        }
        return originalWriteText(text);
      };
      setTimeout(() => {
        if (isOverriding) {
          isOverriding = false;
          navigator.clipboard.writeText = originalWriteText;
        }
      }, 100);
    };
    const wrapper = wrapperRef.current;
    wrapper.addEventListener('click', handleClick, true);
    return () => {
      wrapper.removeEventListener('click', handleClick, true);
      if (navigator.clipboard.writeText !== originalWriteText) {
        navigator.clipboard.writeText = originalWriteText;
      }
    };
  }, [copyText]);
  return <div ref={wrapperRef}>
      <CodeBlock filename={filename} icon={icon} language={language} lines highlight={highlight}>
        {displayText}
      </CodeBlock>
    </div>;
};

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 />

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">
  \*\*前提条件：\*\*開始する前に、以下がインストールされていることを確認してください。

  * **[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 以降

  インストールの確認：`node --version && npm --version`
</Callout>

<Warning>
  `@auth0/auth0-tanstack-start-react` は現在 **ベータ版** (`1.0.0-beta.0`) です。安定版 1.0 のリリースまでに API が変更される可能性があります。
</Warning>

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

このクイックスタートでは、TanStack Start Reactアプリケーションに Auth0 authentication を追加する方法を説明します。Auth0 TanStack Start React SDKを使用して、Login、logout、保護されたroute、ユーザープロファイル情報を備えたサーバーレンダリング型のアプリを構築します。

export function generateRandomString(length) {
  const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
  return Array.from({
    length
  }, () => chars[Math.floor(Math.random() * chars.length)]).join('');
}

export const localEnvSnippet = `AUTH0_DOMAIN={yourDomain}
AUTH0_CLIENT_ID={yourClientId}
AUTH0_CLIENT_SECRET={yourClientSecret}
AUTH0_SECRET=${generateRandomString(32)}
APP_BASE_URL=http://localhost:3000`;

<Steps>
  <Step title="新しいプロジェクトを作成する" stepNumber={1}>
    この Quickstart 用に、新しい TanStack Start プロジェクトを作成します。

    ```shellscript theme={null}
    npx @tanstack/cli@latest create auth0-tanstack-start --blank --package-manager npm -y
    ```

    <Info>
      お使いのマシンで `@tanstack/cli` を初めて実行する場合、npm からインストールの確認を求められます。**y** と入力して続行してください。
    </Info>

    プロジェクトを開きます:

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

  <Step title="Auth0 TanStack Start SDK をインストールする" stepNumber={2}>
    ```shellscript theme={null}
    npm install @auth0/auth0-tanstack-start-react
    ```
  </Step>

  <Step title="Tailwind CSS を追加" stepNumber={3}>
    Tailwind CSS と Vite プラグインをインストールします。

    ```shellscript theme={null}
    npm install tailwindcss @tailwindcss/vite
    ```

    `vite.config.ts` を更新して Tailwind の Plugin を追加し、開発サーバーを `port 3000` に固定します。

    ```typescript vite.config.ts {2,7} lines theme={null}
    import { defineConfig } from 'vite';
    import tailwindcss from '@tailwindcss/vite';
    import { tanstackStart } from '@tanstack/react-start/plugin/vite';
    import viteReact from '@vitejs/plugin-react';

    const config = defineConfig({
      server: { strictPort: true },
      resolve: { tsconfigPaths: true },
      plugins: [tailwindcss(), tanstackStart(), viteReact()],
    });

    export default config;
    ```

    <Callout icon="file-lines" color="#0EA5E9" iconType="regular">
      `strictPort: true` を指定すると、Vite はポートを勝手に切り替えるのではなく、その場でエラーとして停止します。Auth0 アプリケーションのコールバック URL はポート 3000 に固定されているため、ポートが黙って変更されると、何もリッスンしていないポートにブラウザがリダイレクトされ、ログイン画面で承認した後に空白のページから先に進めなくなってしまいます。
    </Callout>

    `src/styles.css` の内容を次の内容に置き換えます。

    ```css src/styles.css lines theme={null}
    @import "tailwindcss";
    ```
  </Step>

  <Step title="プロジェクトファイルを作成" stepNumber={4}>
    Auth0連携に必要な追加ファイルを作成します。

    <CodeGroup>
      ```shellscript Mac/Linux theme={null}
      mkdir -p src/components && touch .env src/start.ts src/auth.server.ts src/components/LoginButton.tsx src/components/LogoutButton.tsx src/components/Profile.tsx src/routes/dashboard.tsx
      ```

      ```powershell Windows theme={null}
      New-Item -ItemType Directory -Force -Path src/components
      New-Item -ItemType File -Path .env, src/start.ts, src/auth.server.ts, src/components/LoginButton.tsx, src/components/LogoutButton.tsx, src/components/Profile.tsx, src/routes/dashboard.tsx
      ```
    </CodeGroup>
  </Step>

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

    Auth0アプリをセットアップする方法は3つあります。Quick Setupツールを使用する (推奨) 、CLIコマンドを実行する、またはAuth0 Dashboardから手動で構成する、のいずれかです。

    <Tabs>
      <Tab title="クイックセットアップ（推奨）">
        Auth0 アプリを作成し、適切な設定値が事前入力された `.env` ファイルをコピーします。

        <CreateInteractiveApp placeholderText="TanStack Start" appType="regular_web" allowedCallbackUrls={["http://localhost:3000/auth/callback"]} allowedLogoutUrls={["http://localhost:3000"]} allowedOriginUrls={["http://localhost:3000"]} />

        <AuthCodeBlock children={localEnvSnippet} language="shellscript" filename=".env" />
      </Tab>

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

        <CodeGroup>
          ```shellscript Mac theme={null}
          # Auth0 CLI をインストール（未インストールの場合）
          brew tap auth0/auth0-cli && brew install auth0

          # Auth0 アプリをセットアップし、.env ファイルを生成
          auth0 qs setup --app --type regular --name "My App" --port 3000
          ```

          ```powershell Windows theme={null}
          # Auth0 CLI をインストール（未インストールの場合）
          scoop bucket add auth0 https://github.com/auth0/scoop-auth0-cli.git
          scoop install auth0

          # Auth0 アプリをセットアップし、.env ファイルを生成
          auth0 qs setup --app --type regular --name "My App" --port 3000
          ```
        </CodeGroup>

        <Callout icon="file-lines" color="#0EA5E9" iconType="regular">
          このコマンドは次の処理を行います：

          1. 認証済みかどうかを確認します (必要に応じてログインを求めます)
          2. `http://localhost:3000` 向けに設定された Auth0 Regular Web Application を作成します
          3. `AUTH0_DOMAIN`、`AUTH0_CLIENT_ID`、`AUTH0_CLIENT_SECRET`、`AUTH0_SECRET`、`APP_BASE_URL` を含む `.env` ファイルを生成します
        </Callout>
      </Tab>

      <Tab title="Auth0 Dashboard">
        手順 4 で作成した `.env` ファイルを開き、次の内容を追加します：

        ```shellscript .env theme={null}
        AUTH0_DOMAIN=YOUR_AUTH0_APP_DOMAIN
        AUTH0_CLIENT_ID=YOUR_AUTH0_APP_CLIENT_ID
        AUTH0_CLIENT_SECRET=YOUR_AUTH0_APP_CLIENT_SECRET
        AUTH0_SECRET=YOUR_LONG_RANDOM_SECRET_HERE
        APP_BASE_URL=http://localhost:3000
        ```

        **安全な AUTH0\_SECRET を生成する：**

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

        出力された値をコピーし、`.env` 内の `YOUR_LONG_RANDOM_SECRET_HERE` と置き換えます。必ず 64 文字の 16 進数である必要があります。

        次に、Auth0 アプリケーションを設定します：

        1. [Auth0 Dashboard](https://manage.auth0.com/dashboard/) に移動します
        2. **アプリケーション** > **アプリケーション** > **Create Application** を選択します
        3. アプリの名前を入力し、アプリの種類として **Regular Web Application** を選択して、**Create** を選択します
        4. Application Details ページの **設定** タブに切り替えます
        5. `.env` ファイル内の `YOUR_AUTH0_APP_DOMAIN`、`YOUR_AUTH0_APP_CLIENT_ID`、`YOUR_AUTH0_APP_CLIENT_SECRET` を、dashboard に表示されている **Domain**、**Client ID**、**Client Secret** の値に置き換えます

        <Warning>
          **重要：** `AUTH0_DOMAIN`、`AUTH0_CLIENT_ID`、`AUTH0_CLIENT_SECRET`、`AUTH0_SECRET`、`APP_BASE_URL` はサーバー側でのみ読み取られます。これらに `VITE_` を付けないでください。付けると、値が client-side の JavaScript にバンドルされてしまいます。
        </Warning>

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

        **Allowed Callback URLs：**

        ```
        http://localhost:3000/auth/callback
        ```

        **Allowed Logout URLs：**

        ```
        http://localhost:3000
        ```

        **Allowed Web Origins：**

        ```
        http://localhost:3000
        ```

        <Info>
          * Allowed Callback URLs は、authentication 後にユーザーを安全にアプリケーションへ戻すための重要なセキュリティ対策です。一致する URL がないと、ログインプロセスは失敗し、end user はアプリにアクセスできず Auth0 のエラーページで止まってしまいます。
          * Allowed Logout URLs は、サインアウト時にシームレスな end user 体験を提供するために欠かせません。一致する URL がないと、end user は logout 後にアプリケーションへリダイレクトされず、汎用的な Auth0 のページに取り残されてしまいます。
          * Allowed Web Origins は silent authentication に不可欠です。設定されていないと、ユーザーがページを再読み込みしたり、後からアプリに戻ったりした際にログアウトされてしまいます。
        </Info>
      </Tab>
    </Tabs>
  </Step>

  <Step title="Auth0サーバーのインスタンスを作成する" stepNumber={6}>
    `src/auth.server.ts` に Auth0 server インスタンスを追加します。Auth0 server インスタンスは、先ほど設定した environment variables から構成を読み込みます。

    ```typescript src/auth.server.ts lines theme={null}
    import { auth0Server } from '@auth0/auth0-tanstack-start-react/server';

    export const auth0 = auth0Server();
    ```
  </Step>

  <Step title="Auth0 middleware を登録する" stepNumber={7}>
    Auth0 の request middleware を登録するために、`src/start.ts` に以下を追加します。

    ```typescript src/start.ts lines theme={null}
    import { createStart } from '@tanstack/react-start';
    import { auth0Middleware } from '@auth0/auth0-tanstack-start-react/server/middleware';

    export const startInstance = createStart(() => ({
      requestMiddleware: [auth0Middleware()],
    }));
    ```

    <Callout icon="file-lines" color="#0EA5E9" iconType="regular">
      `start.ts` はクライアントバンドルにもコンパイルされるため、`auth0Middleware` は `/server` バレルではなく `/server/middleware` サブパスからインポートしてください。
    </Callout>

    <Info>
      このミドルウェアは、以下の認証ルートを自動的にマウントします。

      * `/auth/login` - Login ルート
      * `/auth/callback` - コールバックルート
      * `/auth/logout` - Logout ルート
      * `/auth/profile` - ユーザープロファイルルート
      * `/auth/backchannel-logout` - バックチャネル logout ルート
    </Info>
  </Step>

  <Step title="Auth0をrouterに組み込む" stepNumber={8}>
    `src/router.tsx` を更新し、Router のコンテキストが Auth0 で解決された認証 state を保持するようにします。TanStack Start では、このファイルで `getRouter` という名前の関数を export する必要があります。

    ```typescript src/router.tsx {2,3,7,9,13} lines theme={null}
    import { createRouter as createTanStackRouter } from '@tanstack/react-router';
    import { auth0RouterContext } from '@auth0/auth0-tanstack-start-react/client';
    import type { Auth0RouterContext } from '@auth0/auth0-tanstack-start-react/types';
    import { routeTree } from './routeTree.gen';

    export interface RouterContext {
      auth0: Auth0RouterContext;
    }

    export function getRouter() {
      const router = createTanStackRouter({
        routeTree,
        scrollRestoration: true,
        defaultPreload: 'intent',
        defaultPreloadStaleTime: 0,
        context: { auth0: auth0RouterContext } satisfies RouterContext,
      });

      return router;
    }

    declare module '@tanstack/react-router' {
      interface Register {
        router: ReturnType<typeof getRouter>;
      }
    }
    ```
  </Step>

  <Step title="ルートルートを更新する" stepNumber={9}>
    `src/routes/__root.tsx` を更新して、レンダリング前に認証 state を解決し、アプリを `Auth0Provider` でラップします。

    ```typescript src/routes/__root.tsx expandable lines theme={null}
    import {
      HeadContent,
      Scripts,
      createRootRouteWithContext,
    } from '@tanstack/react-router';
    import { Auth0Provider, auth0BeforeLoad } from '@auth0/auth0-tanstack-start-react/client';

    import type { RouterContext } from '../router';
    import appCss from '../styles.css?url';

    export const Route = createRootRouteWithContext<RouterContext>()({
      beforeLoad: auth0BeforeLoad(),
      head: () => ({
        meta: [
          { charSet: 'utf-8' },
          { name: 'viewport', content: 'width=device-width, initial-scale=1' },
          { title: 'Auth0 + TanStack Start' },
        ],
        links: [{ rel: 'stylesheet', href: appCss }],
      }),
      shellComponent: RootDocument,
    });

    function RootDocument({ children }: { children: React.ReactNode }) {
      return (
        <html lang="en">
          <head>
            <HeadContent />
          </head>
          <body className="antialiased">
            <Auth0Provider>{children}</Auth0Provider>
            <Scripts />
          </body>
        </html>
      );
    }
    ```

    <Callout icon="file-lines" color="#0EA5E9" iconType="regular">
      これにより `createRootRoute` が `createRootRouteWithContext<RouterContext>()` に置き換わり、ルートツリーの型に `context.auth0` を含められるようになります。
    </Callout>
  </Step>

  <Step title="Login、Logout、プロファイルコンポーネントを作成する" stepNumber={10}>
    ステップ 4 で作成したファイルに、コンポーネントのコードを追加します:

    <AuthCodeGroup>
      ```typescript src/components/LoginButton.tsx lines theme={null}
      import { useLogin } from "@auth0/auth0-tanstack-start-react/client";

      export default function LoginButton() {
        const login = useLogin();

        return (
          <button
            onClick={() => login("/dashboard")}
            className="w-full text-center inline-block px-6 py-3 bg-gradient-to-b from-[#2d2d42] to-[#161620] hover:opacity-90 text-white font-medium rounded-full text-[14px] transition-opacity"
          >
            Log In
          </button>
        );
      }
      ```

      ```typescript src/components/LogoutButton.tsx lines theme={null}
      import { useLogout } from "@auth0/auth0-tanstack-start-react/client";

      export default function LogoutButton() {
        const logout = useLogout();

        return (
          <button
            onClick={() => logout()}
            className="w-full text-center inline-block px-6 py-3 bg-[#f0f0f0] hover:bg-gray-200 text-gray-600 font-medium rounded-full text-[14px] transition-colors"
          >
            Log Out
          </button>
        );
      }
      ```

      ```typescript src/components/Profile.tsx lines theme={null}
      import { useUser } from "@auth0/auth0-tanstack-start-react/client";

      function getInitials(name?: string | null, email?: string | null): string {
        if (name) {
          const parts = name.trim().split(" ");
          return parts.length >= 2
            ? `${parts[0][0]}${parts[1][0]}`.toUpperCase()
            : parts[0].slice(0, 2).toUpperCase();
        }
        if (email) return email.slice(0, 2).toUpperCase();
        return "U";
      }

      export default function Profile() {
        const user = useUser();

        if (!user) return null;

        return (
          <div className="flex items-center gap-2 bg-gray-100 rounded-full py-1.5 pl-1.5 pr-4 text-[12px] text-gray-700 max-w-full">
            <span className="w-7 h-7 bg-gradient-to-b from-[#2d2d42] to-[#161620] rounded-full flex items-center justify-center text-white text-[10px] font-semibold shrink-0">
              {getInitials(user.name, user.email)}
            </span>
            <span className="truncate">{user.email}</span>
          </div>
        );
      }
      ```
    </AuthCodeGroup>

    次に、`src/routes/index.tsx` のプレースホルダーの内容 (スキャフォールドで生成された `Welcome to TanStack Start` ページ) を、以下の内容に置き換えます。

    ```typescript src/routes/index.tsx lines theme={null}
    import { createFileRoute } from "@tanstack/react-router";
    import { SignedIn, SignedOut } from "@auth0/auth0-tanstack-start-react/client";
    import LoginButton from "../components/LoginButton";
    import LogoutButton from "../components/LogoutButton";
    import Profile from "../components/Profile";

    export const Route = createFileRoute("/")({
      component: Home,
    });

    function Home() {
      return (
        <main className="min-h-screen bg-[#efefef] flex flex-col items-center justify-center gap-4 px-6 py-12">
          <div className="bg-white rounded-[28px] shadow-[0_4px_32px_rgba(0,0,0,0.08)] px-12 py-14 flex flex-col items-center gap-4 w-[360px]">
            <svg width="68" height="68" viewBox="0 0 68 68" fill="none" xmlns="http://www.w3.org/2000/svg" className="mb-1">
              <g filter="url(#filter0_di)">
                <rect x="2" y="2" width="64" height="64" rx="16" fill="url(#paint0_linear)"/>
                <rect x="2.5" y="2.5" width="63" height="63" rx="15.5" stroke="#252525"/>
                <path d="M34.0002 18C25.1572 18 18 25.1669 18 34C18 42.8432 25.1672 50 34.0002 50C42.8333 50 50 42.8331 50 34C50 25.1669 42.8433 18 34.0002 18ZM43.9172 43.8971C43.9172 43.9071 43.9069 43.9072 43.9069 43.9172C43.9069 43.9172 43.8969 43.9272 43.8868 43.9272C43.144 44.65 41.9796 44.7303 41.0662 44.2585L40.0228 43.7265C36.2487 41.7792 31.7619 41.7792 27.9777 43.7265L26.9338 44.2585C26.0103 44.7303 24.8459 44.65 24.1132 43.9272C24.1132 43.9272 24.1031 43.9172 24.0931 43.9172C24.0931 43.9172 24.0828 43.9071 24.0828 43.8971C23.3601 43.1543 23.2797 41.9899 23.7515 41.0765L24.2837 40.0326C26.231 36.2585 26.231 31.7717 24.2837 27.9975L23.7515 26.9536C23.2797 26.0302 23.3601 24.8657 24.0828 24.133C24.0828 24.1229 24.0931 24.123 24.0931 24.123C24.0931 24.123 24.1031 24.1129 24.1132 24.1129C24.856 23.3902 26.0204 23.3099 26.9338 23.7817L27.9777 24.3137C31.7518 26.261 36.2386 26.261 40.0228 24.3137L41.0662 23.7817C41.9897 23.3099 43.1541 23.3902 43.8868 24.1129C43.8868 24.1129 43.8969 24.123 43.9069 24.123L43.9172 24.133C44.6399 24.8758 44.7203 26.0402 44.2485 26.9536L43.7163 27.9975C41.769 31.7717 41.769 36.2585 43.7163 40.0326L44.2485 41.0765C44.7203 41.9899 44.6499 43.1543 43.9172 43.8971Z" fill="white"/>
              </g>
              <defs>
                <filter id="filter0_di" x="0" y="0" width="68" height="68" filterUnits="userSpaceOnUse" colorInterpolationFilters="sRGB">
                  <feFlood floodOpacity="0" result="BackgroundImageFix"/>
                  <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
                  <feMorphology radius="2" operator="dilate" in="SourceAlpha" result="effect1_dropShadow"/>
                  <feOffset/>
                  <feComposite in2="hardAlpha" operator="out"/>
                  <feColorMatrix type="matrix" values="0 0 0 0 0.117647 0 0 0 0 0.129412 0 0 0 0 0.164706 0 0 0 0.12 0"/>
                  <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow"/>
                  <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow" result="shape"/>
                  <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
                  <feOffset dy="-1"/>
                  <feGaussianBlur stdDeviation="0.5"/>
                  <feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
                  <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.04 0"/>
                  <feBlend mode="normal" in2="shape" result="effect2_innerShadow"/>
                </filter>
                <linearGradient id="paint0_linear" x1="34" y1="2" x2="34" y2="66" gradientUnits="userSpaceOnUse">
                  <stop/>
                  <stop offset="1" stopColor="#677190"/>
                </linearGradient>
              </defs>
            </svg>

            <SignedIn>
              <h1 className="text-[17px] font-bold text-gray-900 tracking-tight">Your account</h1>
              <div className="w-full h-px bg-gray-100" />
              <Profile />
              <LogoutButton />
            </SignedIn>
            <SignedOut>
              <h1 className="text-[17px] font-bold text-gray-900 tracking-tight">Welcome to Auth0 + TanStack Start</h1>
              <p className="text-[13px] text-gray-400 text-center leading-relaxed -mt-2">
                Get started by logging in to your account
              </p>
              <div className="h-3" />
              <LoginButton />
            </SignedOut>
          </div>

          <div className="flex items-center gap-1.5 text-[11px] text-gray-400">
            <span>Powered by</span>
            <img
              src="https://cdn.auth0.com/quantum-assets/dist/latest/logos/auth0/auth0-lockup-en-onlight.svg"
              alt="Auth0"
              className="h-3 opacity-40"
            />
          </div>
        </main>
      );
    }
    ```

    <Info>
      `useLogin` と `useLogout` は、client-side の Router による遷移ではなく、ブラウザー全体のナビゲーションを行います。これは `/auth/*` がサーバー側の middleware で処理され、session cookie を有効にするにはページの再読み込みが必要なためです。
    </Info>
  </Step>

  <Step title="ルートを保護する" stepNumber={11}>
    `requireAuth` ガードを使用して、保護された `/dashboard` route を `src/routes/dashboard.tsx` に追加します。この route は、HTML がブラウザーに送信される前にサーバー側で未認証のユーザーを `/auth/login` にリダイレクトします。

    ```typescript src/routes/dashboard.tsx lines theme={null}
    import { createFileRoute } from "@tanstack/react-router";
    import { requireAuth, useUser } from "@auth0/auth0-tanstack-start-react/client";
    import LogoutButton from "../components/LogoutButton";
    import Profile from "../components/Profile";

    export const Route = createFileRoute("/dashboard")({
      beforeLoad: requireAuth({ returnTo: "/dashboard" }),
      component: Dashboard,
    });

    function Dashboard() {
      const user = useUser();

      return (
        <main className="min-h-screen bg-[#efefef] flex flex-col items-center justify-center gap-4 px-6 py-12">
          <div className="bg-white rounded-[28px] shadow-[0_4px_32px_rgba(0,0,0,0.08)] px-12 py-14 flex flex-col items-center gap-4 w-[360px]">
            <h1 className="text-[17px] font-bold text-gray-900 tracking-tight">Welcome, {user?.name}!</h1>
            <div className="w-full h-px bg-gray-100" />
            <Profile />
            <LogoutButton />
          </div>
        </main>
      );
    }
    ```
  </Step>

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

    <Info>
      アプリは [http://localhost:3000](http://localhost:3000) でアクセスできます。
    </Info>
  </Step>
</Steps>

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

  ここまでで、[localhost](http://localhost:3000/) 上で Auth0 Loginページが問題なく動作しているはずです
</Check>
