HelloJohn / docs
SDKsReact SDK

Route Protection

Protect routes in React applications — the Protected component, useProtected hook, and redirect patterns with the HelloJohn React SDK.

Route Protection

@hellojohn/react provides tools to restrict route access to authenticated users, specific roles, and organization members.


<Protected>

Wrap any route or component to require authentication:

import { Protected } from "@hellojohn/react";

function App() {
  return (
    <Routes>
      <Route path="/" element={<Home />} />
      <Route
        path="/dashboard"
        element={
          <Protected redirectTo="/sign-in">
            <Dashboard />
          </Protected>
        }
      />
    </Routes>
  );
}

Props:

PropTypeDefaultDescription
redirectTostring"/sign-in"Redirect URL if not authenticated
fallbackReactNodenullElement to show while loading
rolestringRequire a specific organization role
orgIdstringRequire membership in a specific org

Protecting by Role

// Only org owners and admins can access
<Protected role="admin" redirectTo="/dashboard">
  <AdminSettings />
</Protected>

// Owners only
<Protected role="owner" redirectTo="/dashboard">
  <BillingPage />
</Protected>

Next.js App Router

Wrap layouts with <Protected> to protect entire route segments:

// app/dashboard/layout.tsx
import { Protected } from "@hellojohn/react";

export default function DashboardLayout({ children }) {
  return (
    <Protected redirectTo="/sign-in">
      <DashboardShell>{children}</DashboardShell>
    </Protected>
  );
}

useProtected Hook

For programmatic protection:

import { useProtected } from "@hellojohn/react";

function SecurePage() {
  // Redirects to /sign-in if not authenticated
  // Returns null while loading
  const { user } = useProtected({ redirectTo: "/sign-in" });

  if (!user) return null;

  return <div>Hello, {user.name}</div>;
}

Options:

OptionTypeDescription
redirectTostringWhere to send unauthenticated users
rolestringRequired organization role
onUnauthenticated() => voidCustom handler instead of redirect

Conditional Rendering

Show content based on authentication state without redirecting:

import { useSession, useUser } from "@hellojohn/react";

function NavBar() {
  const { session } = useSession();
  const { user } = useUser();

  return (
    <nav>
      <Logo />
      {session ? (
        <UserButton />
      ) : (
        <a href="/sign-in">Sign in</a>
      )}
    </nav>
  );
}

Role-Based Access Control

Combine useOrganization with conditional rendering for RBAC:

import { useOrganization } from "@hellojohn/react";

function DeleteOrgButton() {
  const { membership } = useOrganization();

  // Only show for owners
  if (membership?.role !== "owner") return null;

  return (
    <button className="btn-destructive" onClick={handleDelete}>
      Delete Organization
    </button>
  );
}

Loading States

Always handle the loading state to avoid flashes of unauthenticated content:

import { useSession } from "@hellojohn/react";

function ProtectedPage() {
  const { session, isLoading } = useSession();

  if (isLoading) {
    return <LoadingSpinner />;
  }

  if (!session) {
    // Redirect programmatically
    window.location.href = "/sign-in";
    return null;
  }

  return <PageContent />;
}

On this page