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

# Add Login to Your TanStack Start Application

> This guide demonstrates how to integrate Auth0 with a TanStack Start React application using the Auth0 TanStack Start React SDK.

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('Application name is required');
        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 : 'Failed to create application';
        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">
          Create Auth0 App
        </span>
        <div className="w-full flex gap-2">
          <input id="app-name" name={name} className="
              w-full max-w-[448px] h-11 py-2 px-4 
              border rounded-lg border-gray-950/10 dark:border-white/10 
              text-gray-900 dark:text-gray-200
              focus:outline-none dark:focus:outline-none
            " placeholder={`My ${placeholderText} App`} value={name} onChange={e => setName(e.target.value)} />
          <Button onClick={handleSubmit}>
            {isLoading ? 'Creating...' : 'Create'}
          </Button>
        </div>
        {error && <p className="text-red-500">{error}</p>}
      </Card>;
  };
  const SignInForm = () => {
    return <Card className="items-center">
        <Button onClick={login}>Log in</Button> <span>to create the app</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">
  **Prerequisites:** Before you begin, ensure you have the following installed:

  * **[Node.js](https://nodejs.org/en/download)** 20 LTS or newer
  * **[npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm)** 10+ or **[yarn](https://classic.yarnpkg.com/lang/en/docs/install/)** 1.22+ or **[pnpm](https://pnpm.io/installation)** 8+

  Verify installation: `node --version && npm --version`
</Callout>

<Warning>
  `@auth0/auth0-tanstack-start-react` is currently in **beta** (`1.0.0-beta.0`). The API may change before the stable 1.0 release.
</Warning>

## Get Started

This quickstart demonstrates how to add Auth0 authentication to a TanStack Start React application. You'll build a server-rendered app with login, logout, protected routes, and user profile information using the Auth0 TanStack Start React SDK.

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="Create a new project" stepNumber={1}>
    Scaffold a new TanStack Start project for this Quickstart:

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

    <Info>
      If this is the first time you've run `@tanstack/cli` on your machine, npm asks to confirm installing it: answer **y** to continue.
    </Info>

    Open the project:

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

  <Step title="Install the Auth0 TanStack Start SDK" stepNumber={2}>
    ```shellscript theme={null}
    npm install @auth0/auth0-tanstack-start-react
    ```
  </Step>

  <Step title="Add Tailwind CSS" stepNumber={3}>
    Install Tailwind CSS and its Vite plugin:

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

    Update `vite.config.ts` to add the Tailwind plugin and lock the dev server to `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">
      Vite fails immediately when you use `strictPort: true`  instead of silently switching ports. Your Auth0 application's callback URL is locked to port 3000, and since the browser gets redirected to a port nothing is listening on, a silent port change leaves you stuck on a blank page after approving the login screen.
    </Callout>

    Replace the contents of `src/styles.css` with:

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

  <Step title="Create project files" stepNumber={4}>
    Create the additional files you need for Auth0 integration:

    <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="Setup your Auth0 App" stepNumber={5}>
    Next up, you need to create a new app on your Auth0 tenant and add the environment variables to your project.

    You have three options to set up your Auth0 app: use the Quick Setup tool (recommended), run a CLI command, or configure manually via the Dashboard:

    <Tabs>
      <Tab title="Quick Setup (recommended)">
        Create an Auth0 app and copy the pre-filled `.env` file with the right configuration values.

        <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">
        Run the following command in your project's root directory to create an Auth0 app and generate an `.env` file:

        <CodeGroup>
          ```shellscript Mac theme={null}
          # Install Auth0 CLI (if not already installed)
          brew tap auth0/auth0-cli && brew install auth0

          # Set up Auth0 app and generate an .env file
          auth0 qs setup --app --type regular --name "My App" --port 3000
          ```

          ```powershell Windows theme={null}
          # Install Auth0 CLI (if not already installed)
          scoop bucket add auth0 https://github.com/auth0/scoop-auth0-cli.git
          scoop install auth0

          # Set up Auth0 app and generate .env file
          auth0 qs setup --app --type regular --name "My App" --port 3000
          ```
        </CodeGroup>

        <Callout icon="file-lines" color="#0EA5E9" iconType="regular">
          This command:

          1. Checks if you're authenticated (and prompt for login if needed)
          2. Creates an Auth0 Regular Web Application configured for `http://localhost:3000`
          3. Generates an `.env` file with `AUTH0_DOMAIN`, `AUTH0_CLIENT_ID`, `AUTH0_CLIENT_SECRET`, `AUTH0_SECRET`, and `APP_BASE_URL`
        </Callout>
      </Tab>

      <Tab title="Dashboard">
        Open the `.env` file you created in Step 4 and add:

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

        **Generate a secure AUTH0\_SECRET:**

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

        Copy the output and replace `YOUR_LONG_RANDOM_SECRET_HERE` in `.env`. This must be exactly 64 hexadecimal characters.

        Then configure your Auth0 application:

        1. Navigate to the [Auth0 Dashboard](https://manage.auth0.com/dashboard/)
        2. Select **Applications** > **Applications** > **Create Application**
        3. Enter a name for your app, select **Regular Web Application** as the app type and select **Create**
        4. Switch to the **Settings** tab on the Application Details page
        5. Replace `YOUR_AUTH0_APP_DOMAIN`, `YOUR_AUTH0_APP_CLIENT_ID`, and `YOUR_AUTH0_APP_CLIENT_SECRET` in the `.env` file with the **Domain**, **Client ID**, and **Client Secret** values from the dashboard

        <Warning>
          **Critical:** `AUTH0_DOMAIN`, `AUTH0_CLIENT_ID`, `AUTH0_CLIENT_SECRET`, `AUTH0_SECRET`, and `APP_BASE_URL` are read on the server only. Never prefix them with `VITE_`, or their values will be bundled into client-side JavaScript.
        </Warning>

        Finally, on the **Settings** tab of your Application Details page, configure the following URLs:

        **Allowed Callback URLs:**

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

        **Allowed Logout URLs:**

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

        **Allowed Web Origins:**

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

        <Info>
          * Allowed Callback URLs are a critical security measure to ensure users are safely returned to your application after authentication. Without a matching URL, the login process will fail, and end users will be blocked by an Auth0 error page instead of accessing your app.
          * Allowed Logout URLs are essential for providing a seamless end user experience upon sign out. Without a matching URL, end users are not be redirected back to your application after logout and are instead left on a generic Auth0 page.
          * Allowed Web Origins is critical for silent authentication. Without it, users are logged out when they refresh the page or return to your app later.
        </Info>
      </Tab>
    </Tabs>
  </Step>

  <Step title="Create the Auth0 server instance" stepNumber={6}>
    Add the Auth0 server instance to `src/auth.server.ts`. The Auth0 server instance reads the configuration from the environment variables you just set:

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

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

  <Step title="Register the Auth0 middleware" stepNumber={7}>
    Add the following to `src/start.ts` to register the Auth0 request middleware:

    ```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">
      Import `auth0Middleware` from the `/server/middleware` subpath, not the `/server` barrel, since `start.ts` is also compiled into the client bundle.
    </Callout>

    <Info>
      This middleware automatically mounts the following authentication routes:

      * `/auth/login` - Login route
      * `/auth/callback` - Callback route
      * `/auth/logout` - Logout route
      * `/auth/profile` - User profile route
      * `/auth/backchannel-logout` - Backchannel logout route
    </Info>
  </Step>

  <Step title="Wire Auth0 into the router" stepNumber={8}>
    Update `src/router.tsx` so the router context carries Auth0's resolved auth state. TanStack Start requires this file to export a function named `getRouter`:

    ```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="Update the root route" stepNumber={9}>
    Update `src/routes/__root.tsx` to resolve auth state before render and wrap the app in `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">
      This replaces `createRootRoute` with `createRootRouteWithContext<RouterContext>()` so type the route tree as `context.auth0`.
    </Callout>
  </Step>

  <Step title="Create Login, Logout and Profile Components" stepNumber={10}>
    Add the component code to the files created in Step 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>

    Then replace the placeholder content of `src/routes/index.tsx` (the `Welcome to TanStack Start` page from the scaffold) with:

    ```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` and `useLogout` perform a full browser navigation rather than a client-side router transition because `/auth/*` is handled by the server middleware and the session cookie requires a page reload to take effect.
    </Info>
  </Step>

  <Step title="Protect a route" stepNumber={11}>
    Add a protected `/dashboard` route to `src/routes/dashboard.tsx` using the `requireAuth` guard. It redirects unauthenticated users to `/auth/login` on the server before any HTML is sent to the browser:

    ```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="Run your app" stepNumber={12}>
    ```shellscript theme={null}
    npm run dev
    ```

    <Info>
      Your app is available at [http://localhost:3000](http://localhost:3000).
    </Info>
  </Step>
</Steps>

<Check>
  **Checkpoint**

  You should now have a fully functional Auth0 login page running on your [localhost](http://localhost:3000/)
</Check>
