Skip to main content

Provider Setup

The DeploymentProvider component wraps your application and provides authentication context to all child components.

Basic Setup

// app/routes/root.tsx
import { Outlet } from 'react-router'
import { DeploymentProvider } from '@wacht/react-router'

export async function loader() {
  return {
    publicKey: process.env.WACHT_PUBLIC_KEY
  }
}

export default function Root({ loaderData }: Route.ComponentProps) {
  return (
    <html>
      <body>
        <DeploymentProvider publicKey={loaderData.publicKey}>
          <Outlet />
        </DeploymentProvider>
      </body>
    </html>
  )
}

Provider Props

PropTypeRequiredDescription
publicKeystringYesYour Wacht deployment public key
uiOverwritesDeploymentUISettingsNoCustom UI settings

UI Customization

Customize the appearance of Wacht components:
import { DeploymentProvider } from '@wacht/react-router'

export default function Root({ loaderData }: Route.ComponentProps) {
  return (
    <DeploymentProvider
      publicKey={loaderData.publicKey}
      uiOverwrites={{
        primaryColor: '#4f46e5',
        borderRadius: '8px',
        fontFamily: 'Inter, sans-serif',
        buttonColor: '#ffffff',
        buttonTextColor: '#4f46e5'
      }}
    >
      <Outlet />
    </DeploymentProvider>
  )
}

DeploymentUISettings

interface DeploymentUISettings {
  primaryColor?: string          // Primary brand color (default: #4f46e5)
  borderRadius?: string          // Border radius for components (default: 8px)
  fontFamily?: string            // Font family (default: system-ui)
  buttonColor?: string           // Button background color
  buttonTextColor?: string       // Button text color
  inputBackgroundColor?: string   // Input background color
  inputBorderColor?: string       // Input border color
  errorColor?: string            // Error message color
  successColor?: string          // Success message color
}

Environment Configuration

Required Environment Variables

# .env
WACHT_PUBLIC_KEY=your_public_key_here

Optional Environment Variables

# Override the backend URL (for development)
WACHT_FRONTEND_HOST=https://your-app.wacht.io

Routing Configuration

Auth Routes

Create dedicated routes for authentication:
// app/routes/signin.tsx
import { SignInForm } from '@wacht/react-router'

export default function SignIn() {
  return <SignInForm />
}
// app/routes/signup.tsx
import { SignUpForm } from '@wacht/react-router'

export default function SignUp() {
  return <SignUpForm />
}

SSO Callback Route

Required for OAuth authentication:
// app/routes/auth.callback.tsx
import { SSOCallback } from '@wacht/react-router'

export default function AuthCallback() {
  return (
    <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '100vh' }}>
      <SSOCallback />
    </div>
  )
}
For magic link authentication:
// app/routes/verify-magic-link.tsx
import { MagicLinkVerification } from '@wacht/react-router'

export default function VerifyMagicLink() {
  return <MagicLinkVerification />
}

Route Protection

Using Conditional Components

import { SignedIn, SignedOut, NavigateToSignIn } from '@wacht/react-router'

export default function ProtectedPage() {
  return (
    <>
      <SignedOut>
        <NavigateToSignIn />
      </SignedOut>
      <SignedIn>
        <ProtectedContent />
      </SignedIn>
    </>
  )
}

Using Loader Protection

Protect routes at the loader level:
// app/routes/dashboard.tsx
import { useSession } from '@wacht/react-router'
import { redirect } from 'react-router'

export async function loader() {
  const session = await getSession()

  if (!session) {
    return redirect('/signin')
  }

  return { user: session.user }
}

export default function Dashboard({ loaderData }: Route.ComponentProps) {
  return (
    <div>
      <h1>Welcome, {loaderData.user.first_name}!</h1>
    </div>
  )
}

Custom Redirect URLs

Control where users are redirected after authentication:
import { useNavigation } from '@wacht/react-router'

export default function CustomSignin() {
  const { setAfterSignInUrl } = useNavigation()

  const handleSignIn = () => {
    setAfterSignInUrl('/onboarding')
  }

  return (
    <div>
      <button onClick={handleSignIn}>
        Sign In
      </button>
    </div>
  )
}

Post-Authentication Redirects

import { useNavigation } from '@wacht/react-router'

export default function SignUpWithRedirect() {
  const { setAfterSignUpUrl } = useNavigation()

  return (
    <div>
      <SignUpForm />
      <button onClick={() => setAfterSignUpUrl('/welcome')}>
        Redirect to welcome after sign up
      </button>
    </div>
  )
}

Error Handling

Error Boundaries

Wrap your app in an error boundary to catch authentication errors:
// app/routes/root.tsx
import { isRouteErrorResponse, useRouteError } from 'react-router'

export function ErrorBoundary() {
  const error = useRouteError()

  if (isRouteErrorResponse(error)) {
    return (
      <div>
        <h1>{error.status}</h1>
        <p>{error.data.message}</p>
      </div>
    )
  }

  return <div>Something went wrong</div>
}

Error Callbacks

Components accept error callbacks:
import { SSOCallback } from '@wacht/react-router'

export default function AuthCallback() {
  return (
    <SSOCallback
      onError={(error) => {
        console.error('Auth error:', error)
        // Handle error (e.g., redirect to sign-in with error message)
      }}
    />
  )
}

Multi-Tenant Setup

Organization Context

Enable organization-aware routing:
import { useActiveOrganization } from '@wacht/react-router'

export default function OrgDashboard() {
  const { organization } = useActiveOrganization()

  return (
    <div>
      <h1>{organization.name}</h1>
      {/* Organization-specific content */}
    </div>
  )
}

Workspace Context

Enable workspace-aware routing:
import { useActiveWorkspace } from '@wacht/react-router'

export default function WorkspaceSettings() {
  const { workspace } = useActiveWorkspace()

  return (
    <div>
      <h1>{workspace.name}</h1>
      {/* Workspace-specific content */}
    </div>
  )
}

Production Considerations

Deployment Checklist

  • Set WACHT_PUBLIC_KEY environment variable
  • Configure allowed redirect URLs in Wacht dashboard
  • Set up OAuth providers if using social sign-in
  • Configure email delivery for email verification
  • Test SSO callback route locally
  • Enable HTTPS in production

Performance Optimization

// Use route loaders for data fetching
export async function loader() {
  const session = await getSession()

  if (!session) {
    return redirect('/signin')
  }

  // Fetch initial data in parallel
  const [user, organizations] = await Promise.all([
    fetchUser(session.user.id),
    fetchOrganizations()
  ])

  return { user, organizations }
}