SimpleAuth
ReactComponents

Protected

Show children when signed in; otherwise render a fallback.

Overview

Protected shows children when the user is signed in. When signed out it renders fallback (or nothing). While loading it renders null. Optionally pass onUnauthenticated to run a side effect once when the user is not signed in—for example redirecting to login.

Show complements Protected when you need when="email-verified" or a shared loading fallback without wiring fallback on every gate.

Preview

Interactive preview requires JavaScript.

Install

npx @simpleauthjs/react add session

Props

NameTypeRequiredDescription
childrenReactNodeYesContent for authenticated users.
fallbackReactNodeNoShown when not signed in (after loading completes).
onUnauthenticated() => voidNoRuns at most once when the session is known and the user is signed out.

Usage

"use client"

import type { ReactNode } from "react"
import { Protected } from "@/components/simpleauth"
import { useRouter } from "next/navigation"

export function DashboardShell({ children }: { children: ReactNode }) {
  const router = useRouter()

  return (
    <Protected fallback={<p>Please sign in.</p>} onUnauthenticated={() => router.replace("/login")}>
      {children}
    </Protected>
  )
}

Source

Protected is part of the session feature. The scaffolded sources are shown here together with the other session gates.

components/simpleauth/hooks/use-current-user.ts
"use client"

import { useCallback, useEffect, useState } from "react"
import { SimpleAuthError, type MeResponse } from "@simpleauthjs/core"
import { useSimpleAuthClient } from "../provider"

type UseCurrentUserOptions = {
  autoLoad?: boolean
}

function getErrorMessage(error: unknown) {
  if (error instanceof SimpleAuthError) {
    return error.message
  }

  if (error instanceof Error) {
    return error.message
  }

  return "Unable to fetch current user."
}

export function useCurrentUser(options: UseCurrentUserOptions = {}) {
  const { autoLoad = true } = options
  const auth = useSimpleAuthClient()
  const [isLoading, setIsLoading] = useState(Boolean(autoLoad))
  const [error, setError] = useState<string | null>(null)
  const [data, setData] = useState<MeResponse | null>(null)

  const refresh = useCallback(async () => {
    setIsLoading(true)
    setError(null)

    try {
      const response = await auth.me()
      setData(response)
      return response
    } catch (requestError) {
      setData(null)
      setError(getErrorMessage(requestError))
      throw requestError
    } finally {
      setIsLoading(false)
    }
  }, [auth])

  useEffect(() => {
    if (!autoLoad) {
      return
    }

    refresh().catch(() => {})
  }, [autoLoad, refresh])

  return {
    refresh,
    data,
    error,
    isError: Boolean(error),
    isLoading,
  }
}

On this page