Skip to main content

1. Provider setup

import { BrowserRouter } from 'react-router'
import { DeploymentProvider } from '@wacht/react-router'

export function App() {
  return (
    <DeploymentProvider publicKey={import.meta.env.VITE_WACHT_PUBLISHABLE_KEY}>
      <BrowserRouter>{/* routes */}</BrowserRouter>
    </DeploymentProvider>
  )
}

2. Protect a loader

import { json, redirect, type LoaderFunctionArgs } from 'react-router'
import { authenticateRequest } from '@wacht/react-router/server'

export async function loader({ request }: LoaderFunctionArgs) {
  const { auth, headers } = await authenticateRequest(request, {
    publishableKey: process.env.WACHT_PUBLISHABLE_KEY,
  })

  if (!auth.userId) {
    throw redirect('/sign-in', { headers })
  }

  return json({ userId: auth.userId }, { headers })
}

Header propagation contract

authenticateRequest() may rotate/exchange session state and returns response headers that must be preserved.
const { auth, headers } = await authenticateRequest(request, options)
return json(data, { headers })

getAuth vs requireAuth

  • getAuth: returns auth state without forcing protection
  • requireAuth: runs protect() and throws for unauthenticated requests

Hosted Page Authentication

For maximum simplicity, you can utilize Wacht’s zero-configuration hosted authentication pages instead of building custom forms. Secure your UI by leveraging the <SignedIn> and <SignedOut> components, redirecting unauthenticated users seamlessly.
import { SignedIn, SignedOut, NavigateToSignIn } from '@wacht/react-router'

export function Dashboard() {
  return (
    <div>
      <SignedIn>
        <h1>Welcome to your Dashboard</h1>
        {/* Protected application content */}
      </SignedIn>
      <SignedOut>
        <NavigateToSignIn />
      </SignedOut>
    </div>
  )
}