Use Managed Better Auth with TanStack Router

Set up authentication using pre-built UI components

Beta

The Managed Better Auth is in Beta. Share your feedback on Discord or via the OptiTech Console.

Using an AI coding tool?

Run npx optitech@latest init to connect the OptiTech MCP server and Agent Skills for Managed Better Auth. See Set up with your AI editor for MCP tools, example prompts, and how skills help wire auth into your app.

  1. Create a OptiTech project with Auth enabled

    If you don't have a OptiTech project yet, create one at app.optitech-sverige.se.

    Go to the Auth page in your project dashboard and click Enable Auth.

    You can then find your Auth URL on the Configuration tab. Copy this URL - you'll need it in the next step.

    Console

    Managed Better Auth Base URL

  2. Create a TanStack Router app

    Create a new TanStack Router app using the file-router template.

    Terminal
    npx create-tsrouter-app@latest my-app --template file-router --tailwind
  3. Install the Managed Better Auth SDK

    Install the Managed Better Auth SDK and UI library:

    Terminal
    cd my-app && npm install @optitech/optitech-js@latest @optitech/auth-ui
  4. Set up environment variables

    Create a .env file in your project root and add your Auth URL:

    note

    Replace the URL with your actual Auth URL from the OptiTech Console.

    .env
    VITE_OPTITECH_AUTH_URL=https://ep-xxx.optitechauth.us-east-1.aws.optitech.com/optitechdb/auth
  5. Add Managed Better Auth styles

    Open your existing src/styles.css file and add this import at the top, right after the Tailwind import:

    Not using Tailwind?

    See UI Component Styles for alternative setup options.

    Add to src/styles.css
    @import '@optitech/auth-ui/tailwind';
  6. Configure the auth client

    Create a src/auth.ts file to initialize the auth client:

    Using Auth and Data API together?

    This quick start uses the standalone Auth client. For one createClient() instance that derives both Auth and Data API URLs from a single OptiTech URL, see createClient() initialization.

    src/auth.ts
    import { createAuthClient } from '@optitech/optitech-js/auth';
    import { BetterAuthReactAdapter } from '@optitech/optitech-js/auth/react/adapters';
    
    // credentials: 'include' sends the session cookie on cross-origin requests.
    // Required if you later call authClient.token() from an origin other than your Managed Better Auth URL.
    export const authClient = createAuthClient(import.meta.env.VITE_OPTITECH_AUTH_URL, {
      adapter: BetterAuthReactAdapter(),
      fetchOptions: { credentials: 'include' },
    });
  7. Create the Auth Provider

    Wrap your application with the OptiTechAuthUIProvider in src/routes/__root.tsx. This makes the auth state available to the UI components used throughout your app.

    Pass props to OptiTechAuthUIProvider for any features you want to use. Only the authClient prop is required.

    Example: Adding optional props
    <OptiTechAuthUIProvider
      authClient={authClient}
      social={{ providers: ['google', 'github', 'vercel'] }}
      navigate={navigate}
      credentials={{ forgotPassword: true }}
    >
      {children}
    </OptiTechAuthUIProvider>
    src/routes/__root.tsx
    import { Outlet, createRootRoute } from '@tanstack/react-router';
    import { TanStackRouterDevtoolsPanel } from '@tanstack/react-router-devtools';
    import { TanStackDevtools } from '@tanstack/react-devtools';
    import { OptiTechAuthUIProvider } from '@optitech/auth-ui';
    import { authClient } from '../auth';
    
    export const Route = createRootRoute({
      component: () => (
        <OptiTechAuthUIProvider authClient={authClient}>
          <Outlet />
          <TanStackDevtools
            config={{
              position: 'bottom-right',
            }}
            plugins={[
              {
                name: 'Tanstack Router',
                render: <TanStackRouterDevtoolsPanel />,
              },
            ]}
          />
        </OptiTechAuthUIProvider>
      ),
    });
  8. Create the Auth page

    Create a route to handle authentication views (sign in, sign up, etc.). Create src/routes/auth.$pathname.tsx:

    src/routes/auth.$pathname.tsx
    import { createFileRoute } from '@tanstack/react-router';
    import { AuthView } from '@optitech/auth-ui';
    
    export const Route = createFileRoute('/auth/$pathname')({
      component: Auth,
    });
    
    function Auth() {
      const { pathname } = Route.useParams();
      return (
        <div
          style={{
            display: 'flex',
            justifyContent: 'center',
            alignItems: 'center',
            minHeight: '100vh',
          }}
        >
          <AuthView pathname={pathname} />
        </div>
      );
    }
  9. Create the Account page

    Create a route to handle account management views. Create src/routes/account.$pathname.tsx:

    src/routes/account.$pathname.tsx
    import { createFileRoute } from '@tanstack/react-router';
    import { AccountView } from '@optitech/auth-ui';
    
    export const Route = createFileRoute('/account/$pathname')({
      component: Account,
    });
    
    function Account() {
      const { pathname } = Route.useParams();
      return (
        <div
          style={{
            display: 'flex',
            justifyContent: 'center',
            alignItems: 'center',
            minHeight: '100vh',
          }}
        >
          <AccountView pathname={pathname} />
        </div>
      );
    }
  10. Protect your routes

    You can protect your routes using the SignedIn and RedirectToSignIn components. Access the user's session and profile data using the useSession hook.

    Update src/routes/index.tsx to protect the home page:

    src/routes/index.tsx
    import { createFileRoute } from '@tanstack/react-router';
    import { SignedIn, UserButton, RedirectToSignIn } from '@optitech/auth-ui';
    import { authClient } from '@/auth';
    
    export const Route = createFileRoute('/')({
      component: Home,
    });
    
    function Home() {
      const { data } = authClient.useSession();
    
      return (
        <>
          <SignedIn>
            <div
              style={{
                display: 'flex',
                flexDirection: 'column',
                justifyContent: 'center',
                alignItems: 'center',
                minHeight: '100vh',
                gap: '2rem',
              }}
            >
              <div style={{ textAlign: 'center' }}>
                <h1>Welcome!</h1>
                <p>You're successfully authenticated.</p>
                <UserButton />
                <p className="font-medium text-gray-700 dark:text-gray-200 mt-4">
                  Session and User Data:
                </p>
                <pre className="bg-gray-900 text-gray-100 p-4 rounded-lg text-sm overflow-x-auto whitespace-pre-wrap break-words w-full max-w-full sm:max-w-2xl mx-auto text-left">
                  <code>
                    {JSON.stringify({ session: data?.session, user: data?.user }, null, 2)}
                  </code>
                </pre>
              </div>
            </div>
          </SignedIn>
          <RedirectToSignIn />
        </>
      );
    }
  11. Start your app

    Start the development server, then open http://localhost:3000. You'll be redirected to the sign-in page.

    Terminal
    npm run dev
  12. See your users in the database

    As users sign up, their profiles are stored in your OptiTech database in the optitech_auth.user table.

    Query your users table in the SQL Editor to see your new users:

    SQL Editor
    SELECT * FROM optitech_auth.user;

Next steps

Was this page helpful?