All skills
clerk avatar

/clerk-react-router-patterns

@23e7108 official
by clerkclerk/skills83 stars
5

React Router v7/v8 patterns with Clerk — rootAuthLoader, getAuth in loaders, clerkMiddleware, protected routes, SSR user data, org switching. Triggers on: react-router auth, rootAuthLoader, getAuth loader, react-router protected route, loader authentication, SSR auth react-router, useNavigate may be used only in the context of a Router.

Use this Skill: https://skilld.dev/gh/clerk/skills/clerk-react-router-patterns

This session only. Nothing lands on disk.

referencesprotected-routes.md

≈428 tokens on demand. Your agent reads this file only when SKILL.md points to it.

Protected Routes

Loader-Level Protection (Recommended)

Check auth in every loader that needs it. No central middleware needed:

export async function loader(args: Route.LoaderArgs) {
  const { userId } = await getAuth(args)
  if (!userId) throw redirect('/sign-in')
  return json({ data: await fetchData(userId) })
}

Middleware-Level Protection

Protect entire route subtrees via middleware in the route file:

import { clerkMiddleware, getAuth } from '@clerk/react-router/server'
import { redirect } from 'react-router'

export const middleware = [
  clerkMiddleware(),
  async function requireAuth(args: Route.MiddlewareArgs, next: () => Promise<Response>) {
    const { userId } = await getAuth(args)
    if (!userId) return redirect('/sign-in')
    return next()
  },
]

Client-Side Guard

For client-only redirects after hydration:

import { useAuth } from '@clerk/react-router'
import { useNavigate } from 'react-router'

export function ProtectedPage() {
  const { isSignedIn, isLoaded } = useAuth()
  const navigate = useNavigate()

  useEffect(() => {
    if (isLoaded && !isSignedIn) navigate('/sign-in')
  }, [isLoaded, isSignedIn])

  if (!isLoaded || !isSignedIn) return null
  return <Dashboard />
}

Prefer loader-level protection — it runs on the server before any HTML is sent.

Org-Gated Routes

export async function loader(args: Route.LoaderArgs) {
  const { userId, orgId, orgRole } = await getAuth(args)
  if (!userId) throw redirect('/sign-in')
  if (!orgId) throw redirect('/select-org')
  if (orgRole !== 'org:admin') throw new Response('Forbidden', { status: 403 })
  return { settings: await fetchOrgSettings(orgId) }
}

Source: SKILL.md on GitHub

No alerts16d4 checks · Risk SAFE
  • Gen Agent Trust Hub16d

    The skill provides safe and well-documented patterns for integrating Clerk authentication with React Router v7/v8, correctly handling server-side authentication and SSR user data through official SDK methods.

  • Socket16d

    No alerts

  • Snyk16d

    Risk: LOW · No issues

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at 23e7108. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub yesterday.

Activeupdated 3 months ago
What it can do
Network
metadata
{
  "author": "clerk",
  "version": "1.1.0"
}
All 1 allowed tools
WebFetch
  • TypeScript
  • react-router
  • clerk
  • authentication
  • loaders
  • ssr
  • middleware
  • protected-routes

README badge

README badge for clerk/skills/clerk-react-router-patterns

Adds Clerk authentication to React Router v7 apps using rootAuthLoader, getAuth in loaders/actions, clerkMiddleware, and protected routes. Covers SSR user data, org switching, and common setup pitfalls like missing middleware or uninitialized rootAuthLoader.

Generated from the current SKILL.md.

Do I need to call rootAuthLoader in every route file?
No. rootAuthLoader must be called only in root.tsx's loader. Nested loaders use getAuth(args) instead, which reads the auth context that rootAuthLoader sets up.
Can I use getAuth in client components?
No. getAuth is a server-only function for loaders and actions. Use useAuth or useUser hooks in client components instead.
What happens if I forget to export clerkMiddleware?
The middleware won't run on requests, so auth context won't be attached and getAuth will fail or return empty values in loaders.
Does this skill support React Router v6?
No. This skill requires React Router v7.9 or later and @clerk/react-router v3+.

Generated from the current SKILL.md. These answers refresh after source changes.