SimpleAuth
React

Recipes

Common patterns for SimpleAuth React projects beyond the CLI defaults.

These snippets assume you already ran init and added the relevant features. They focus on wiring SimpleAuth into typical Next.js App Router flows.

Protect a Next.js client route

Use useCurrentUser to decide whether to redirect unauthenticated visitors to your login page.

"use client"

import { useEffect } from "react"
import { useRouter } from "next/navigation"
import { useCurrentUser } from "@/components/simpleauth"

export default function DashboardPage() {
  const router = useRouter()
  const { data, isLoading } = useCurrentUser({ autoLoad: true })

  useEffect(() => {
    if (isLoading) return
    if (!data?.user) {
      router.replace("/login")
    }
  }, [data, isLoading, router])

  if (isLoading || !data?.user) {
    return <p>Loading…</p>
  }

  return <p>Welcome, {data.user.email}</p>
}

Redirect after sign-in

Combine onSuccess with the Next.js router so the user lands on their destination immediately after credentials succeed.

"use client"

import { useRouter } from "next/navigation"
import { SignInForm } from "@/components/simpleauth"

export default function LoginPage() {
  const router = useRouter()

  return (
    <SignInForm
      onSuccess={() => {
        router.push("/dashboard")
      }}
    />
  )
}

Sign out from the client

Call logout on the shared browser client, then refresh local UI state.

"use client"

import { useRouter } from "next/navigation"
import { useSimpleAuthClient } from "@/components/simpleauth"

export function SignOutButton() {
  const auth = useSimpleAuthClient()
  const router = useRouter()

  return (
    <button
      type="button"
      onClick={async () => {
        await auth.logout()
        router.push("/")
        router.refresh()
      }}
    >
      Sign out
    </button>
  )
}

Resolve the user on the server

For App Router server components, use the server SDK currentUser helper instead of React hooks. See currentUser in the Server SDK for full options.

import { headers } from "next/headers"
import { createServerSimpleAuthClient } from "@simpleauthjs/core/server"

export default async function ProfilePage() {
  const auth = createServerSimpleAuthClient()
  const { user } = await auth.currentUser({ headers: await headers() })

  if (!user) {
    return <p>Not signed in</p>
  }

  return <p>{user.email}</p>
}

Secret keys stay on the server

Never import @simpleauthjs/core/server from a file marked "use client". The server SDK expects your secret key and must stay in server-only modules.

Forgot password page

Run npx @simpleauthjs/react add forgot-password, then render ForgotPasswordForm on a dedicated route. The form calls forgotPassword and shows a neutral success message (no email enumeration).

import { ForgotPasswordForm } from "@/components/simpleauth"

export default function ForgotPasswordPage() {
  return <ForgotPasswordForm appName="Acme" />
}

Reset password page (App Router)

Run add reset-password. Read the token query param from the reset link and pass it to ResetPasswordForm.

import { ResetPasswordForm } from "@/components/simpleauth"

export default async function ResetPasswordPage({
  searchParams,
}: {
  searchParams: Promise<{ token?: string }>
}) {
  const { token } = await searchParams
  if (!token) {
    return <p>Missing reset token.</p>
  }

  return <ResetPasswordForm token={token} />
}

Verify email page (App Router)

Run add sign-up then add verify-email. Pass the token from the verification URL into VerifyEmailCallback.

import { VerifyEmailCallback } from "@/components/simpleauth"

export default async function VerifyEmailPage({
  searchParams,
}: {
  searchParams: Promise<{ token?: string }>
}) {
  const { token } = await searchParams
  if (!token) {
    return <p>Missing verification token.</p>
  }

  return <VerifyEmailCallback token={token} />
}

Gate content by email verification

Run add session. Use Show with when="email-verified" so UI that requires a confirmed inbox only renders after user.emailVerified is true. Pass fallback to show a placeholder while useAuth is still loading the session.

"use client"

import { Show } from "@/components/simpleauth"

export function VerifiedOnlyBanner() {
  return (
    <Show when="email-verified" fallback={<p className="text-sm text-muted-foreground">Checking session…</p>}>
      <p className="text-sm">Your email is verified.</p>
    </Show>
  )
}

On this page