All skills
clerk avatar

/clerk-react-patterns

@ca5e365 official
by clerkclerk/skills83 stars
5

React SPA auth patterns with @clerk/react for Vite/CRA - ClerkProvider setup, useAuth/useUser/useClerk hooks, React Router protected routes, custom sign-in flows. Triggers on: Vite Clerk setup, React Router auth, useAuth hook, protected route, custom sign-in form React.

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

This session only. Nothing lands on disk.

SKILL.md

≈73 tokens always: the name and description. ≈939 when used: this file. ≈3.7k more on demand in 7 files.

React SPA Patterns

This skill covers @clerk/react for Vite/CRA SPAs. For Next.js use clerk-nextjs-patterns. For TanStack Start use clerk-tanstack-patterns.

What Do You Need?

Task Reference
useAuth / useUser / useClerk hooks references/hooks.md
Protected routes with React Router references/protected-routes.md
Custom sign-in / sign-up forms references/custom-flows.md
React Router v6/v7 integration references/router-integration.md

References

Reference Description
references/hooks.md useAuth, isLoaded guard
references/protected-routes.md ProtectedRoute pattern
references/custom-flows.md useSignIn, useSignUp flows
references/router-integration.md React Router v6/v7 setup

Setup

npm install @clerk/react

.env:

VITE_CLERK_PUBLISHABLE_KEY=pk_...

src/main.tsx:

import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import { ClerkProvider } from '@clerk/react'
import App from './App.tsx'

const PUBLISHABLE_KEY = import.meta.env.VITE_CLERK_PUBLISHABLE_KEY

createRoot(document.getElementById('root')!).render(
  <StrictMode>
    <ClerkProvider publishableKey={PUBLISHABLE_KEY}>
      <App />
    </ClerkProvider>
  </StrictMode>,
)

Mental Model

@clerk/react is client-only — there is no server-side auth(). All auth state comes from hooks.

  • isLoaded must be true before trusting isSignedIn — always guard on isLoaded
  • useClerk() gives access to signOut, openSignIn, openUserProfile and other methods
  • getToken() from useAuth() fetches the session JWT for API calls

Minimal Pattern

import { useAuth } from '@clerk/react'

export function Dashboard() {
  const { isLoaded, isSignedIn, userId } = useAuth()

  if (!isLoaded) return <div>Loading...</div>
  if (!isSignedIn) return <div>Please sign in</div>

  return <div>Hello {userId}</div>
}

Protected Route (React Router v6/v7)

import { Navigate, Outlet } from 'react-router-dom'
import { useAuth } from '@clerk/react'

export function ProtectedRoute() {
  const { isLoaded, isSignedIn } = useAuth()

  if (!isLoaded) return <div>Loading...</div>
  if (!isSignedIn) return <Navigate to="/sign-in" replace />

  return <Outlet />
}
<Routes>
  <Route element={<ProtectedRoute />}>
    <Route path="/dashboard" element={<Dashboard />} />
    <Route path="/settings" element={<Settings />} />
  </Route>
  <Route path="/sign-in" element={<SignIn />} />
</Routes>

Token for API Calls

import { useAuth } from '@clerk/react'

export function DataFetcher() {
  const { getToken } = useAuth()

  async function fetchData() {
    const token = await getToken()
    if (!token) return

    const res = await fetch('/api/data', {
      headers: { Authorization: `Bearer ${token}` },
    })
    return res.json()
  }

  return <button onClick={fetchData}>Load</button>
}

Common Pitfalls

Symptom Cause Fix
isSignedIn is undefined isLoaded is still false Always check isLoaded first
ClerkProvider missing Provider not at root Wrap <App> in main.tsx
Env var undefined Wrong Vite prefix Use VITE_CLERK_PUBLISHABLE_KEY, access via import.meta.env
Token is null User not signed in Null-check getToken() result
Sign-in component shows blank No publishableKey on provider Pass publishableKey explicitly

See Also

  • clerk-setup - Initial Clerk install
  • clerk-custom-ui - Custom flows & appearance
  • clerk-orgs - B2B organizations

Docs

React SDK

Source: SKILL.md on GitHub

No alerts17d4 checks · Risk SAFE
  • Gen Agent Trust Hub17d

    This skill provides standard documentation, reference patterns, and templates for implementing Clerk authentication in React single-page applications. It follows best practices for authentication flows and uses official dependencies.

  • Socket17d

    No alerts

  • Snyk17d

    Risk: LOW · No issues

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

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

Last checked against GitHub yesterday.

Activeupdated 6 months ago
What it can do
Network
metadata
{
  "author": "clerk",
  "version": "1.0.0"
}
All 1 allowed tools
WebFetch
  • React
  • clerk
  • authentication
  • vite
  • react-router
  • hooks
  • spa
  • protected-routes

README badge

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

Provides patterns for @clerk/react authentication in Vite and Create React App SPAs, including ClerkProvider setup, useAuth/useUser/useClerk hooks, React Router protected routes, and custom sign-in flows. Covers client-side auth state management and token retrieval for API calls with React Router v6/v7.

Generated from the current SKILL.md.

Does this skill work with Next.js?
No. This skill is for Vite and Create React App SPAs using @clerk/react. For Next.js, use the clerk-nextjs-patterns skill instead.
Do I need to check isLoaded before using isSignedIn?
Yes. isLoaded must be true before trusting isSignedIn. Always guard on isLoaded first to avoid undefined values.
How do I get a JWT token to send with API requests?
Call getToken() from the useAuth hook, which returns a session JWT. Always null-check the result before using it.
How do I protect routes with React Router?
Create a ProtectedRoute component that checks isLoaded and isSignedIn with useAuth, then redirects unsigned users or renders an Outlet for protected children.

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