clerk-hello-world
A validation workflow to ensure Clerk authentication is working correctly across your application.
Install
mkdir -p .claude/skills/clerk-hello-world && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/7416" && unzip -o skill.zip -d .claude/skills/clerk-hello-world && rm skill.zipInstalls to .claude/skills/clerk-hello-world
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Create your first authenticated request with Clerk.Key capabilities
- →Validate authentication in server components
- →Protect API routes with session verification
- →Retrieve user data in client components
- →Implement server actions with authentication
- →Integrate Clerk with Express.js
How it works
The skill utilizes auth() for lightweight JWT parsing and currentUser() for backend API calls to verify identity across different application layers.
Inputs & outputs
When to use clerk-hello-world
- →Test Clerk authentication integration
- →Verify server component authentication
- →Debug Clerk API route access
- →Test user data retrieval
About this skill
Clerk Hello World
Overview
Make your first authenticated requests using Clerk across server components, client components, API routes, and server actions. Validates your Clerk integration end-to-end.
Prerequisites
- Clerk SDK installed (
clerk-install-authcompleted) - Environment variables configured (
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY,CLERK_SECRET_KEY) - ClerkProvider wrapping application root
- Middleware configured at project root
Instructions
Step 1: Server Component — auth() and currentUser()
// app/dashboard/page.tsx
import { auth, currentUser } from '@clerk/nextjs/server'
import { redirect } from 'next/navigation'
export default async function DashboardPage() {
// auth() is lightweight — reads JWT from the session cookie, no API call
const { userId } = await auth()
if (!userId) redirect('/sign-in')
// currentUser() makes a Backend API call — use sparingly, counts toward rate limit
const user = await currentUser()
return (
<div>
<h1>Hello, {user?.firstName || 'User'}!</h1>
<p>User ID: {userId}</p>
<p>Email: {user?.emailAddresses[0]?.emailAddress}</p>
<p>Created: {user?.createdAt ? new Date(user.createdAt).toLocaleDateString() : 'N/A'}</p>
</div>
)
}
Key distinction: auth() is cheap (JWT parsing, no network). currentUser() is expensive (Backend API call, rate-limited). Prefer auth() when you only need userId, orgId, or sessionClaims.
Step 2: Protected API Route
// app/api/hello/route.ts
import { auth } from '@clerk/nextjs/server'
export async function GET() {
const { userId, orgId, sessionClaims } = await auth()
if (!userId) {
return Response.json({ error: 'Unauthorized' }, { status: 401 })
}
return Response.json({
message: 'Hello from Clerk!',
userId,
orgId: orgId || null,
sessionId: sessionClaims?.sid,
timestamp: new Date().toISOString(),
})
}
Step 3: Client Component with Hooks
'use client'
import { useUser, useAuth, useClerk } from '@clerk/nextjs'
export function AuthTest() {
const { user, isLoaded, isSignedIn } = useUser()
const { getToken, signOut } = useAuth()
const { openUserProfile } = useClerk()
if (!isLoaded) return <div>Loading...</div>
if (!isSignedIn) return <div>Not signed in</div>
const testAPI = async () => {
// getToken() returns the session JWT — use for calling your own API routes
// or external services with Bearer token auth
const token = await getToken()
const res = await fetch('/api/hello', {
headers: { Authorization: `Bearer ${token}` },
})
const data = await res.json()
console.log('API response:', data)
}
return (
<div>
<p>Signed in as: {user.primaryEmailAddress?.emailAddress}</p>
<img src={user.imageUrl} alt="Avatar" width={48} height={48} />
<div className="flex gap-2 mt-4">
<button onClick={testAPI}>Test API</button>
<button onClick={() => openUserProfile()}>Profile</button>
<button onClick={() => signOut()}>Sign Out</button>
</div>
</div>
)
}
Step 4: Server Action with Auth
// app/actions.ts
'use server'
import { auth } from '@clerk/nextjs/server'
export async function greetUser() {
const { userId } = await auth()
if (!userId) throw new Error('Unauthorized')
// Perform server-side work here (DB queries, external API calls, etc.)
return { greeting: `Hello user ${userId}!`, timestamp: new Date().toISOString() }
}
// app/dashboard/greeting.tsx
'use client'
import { greetUser } from '@/app/actions'
import { useState } from 'react'
export function GreetingButton() {
const [msg, setMsg] = useState<string | null>(null)
return (
<div>
<button onClick={async () => {
const result = await greetUser()
setMsg(result.greeting)
}}>
Get Server Greeting
</button>
{msg && <p>{msg}</p>}
</div>
)
}
Step 5: Express.js Hello World
import express from 'express'
import { clerkMiddleware, requireAuth, getAuth } from '@clerk/express'
const app = express()
app.use(clerkMiddleware())
// Public endpoint
app.get('/api/hello', (req, res) => {
const { userId } = getAuth(req)
res.json({
message: userId ? `Hello user ${userId}!` : 'Hello anonymous!',
authenticated: !!userId,
})
})
// Protected endpoint — returns 403 if no valid session
app.get('/api/me', requireAuth(), (req, res) => {
const { userId, orgId } = getAuth(req)
res.json({ userId, orgId })
})
app.listen(3001)
Error Handling
| Error | Cause | Solution |
|---|---|---|
userId is null | User not authenticated | Redirect to /sign-in or check middleware covers route |
currentUser() returns null | Session expired or invalid | Refresh page; ensure middleware is running |
| 401 from API route | Token missing or expired | Include Authorization: Bearer <token> header |
| Hydration mismatch | Server/client state differs | Guard client components with isLoaded check |
auth() was called but Clerk can't detect clerkMiddleware() | Middleware not in project root | Move middleware.ts out of app/ to project root |
Enterprise Considerations
- Use
auth()overcurrentUser()in hot paths to avoid Backend API rate limits - Deduplicate
currentUser()calls with React'scache()function across server components in the same request - For microservices, pass Clerk JWTs between services and verify with
@clerk/backendor@clerk/express - Session token v2 (default since April 2025) uses a more compact format -- ensure downstream JWT consumers are updated
- Custom session claims can be set in Dashboard > Sessions > Customize session token (limit: 1.2KB)
Resources
Next Steps
Proceed to clerk-local-dev-loop for local development workflow setup.
Output
- Minimal Clerk "hello world" that signs in a user and shows identity on a protected page
- Exact install + env steps for the chosen framework
- Next-step links into deeper clerk-pack skills (webhooks, RBAC, production checklist)
Examples
Next.js hello world
User: Smallest possible Clerk + Next.js demo with a protected /me page.
Skill: scaffolds packages, middleware, sign-in UI, and /me reading user id.
Verify keys are live
User: Confirm publishable + secret keys work against Clerk API.
Skill: runs a minimal session/user fetch and reports success or key-mismatch errors.
When not to use it
- →Do not use currentUser() in hot paths to avoid rate limits
- →Do not rely on auth() for network-dependent data
Prerequisites
Limitations
- →currentUser() is rate-limited
- →Middleware must be at project root
How it compares
Unlike manual session management, this workflow provides built-in helpers for both server-side and client-side authentication states.
Compared to similar skills
clerk-hello-world side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| clerk-hello-world (this skill) | 1 | 27d | Review | Beginner |
| nextjs-supabase-auth | 12 | 6mo | No flags | Intermediate |
| better-auth | 5 | 9mo | Review | Intermediate |
| roier-seo | 4 | 6mo | Review | Intermediate |
Try saying
Example prompts that trigger this skill in your AI assistant.
More by jeremylongshore
View all by jeremylongshore →You might also like
nextjs-supabase-auth
davila7
Expert integration of Supabase Auth with Next.js App Router Use when: supabase auth next, authentication next.js, login supabase, auth middleware, protected route.
better-auth
mrgoonie
Implement authentication and authorization with Better Auth - a framework-agnostic TypeScript authentication framework. Features include email/password authentication with verification, OAuth providers (Google, GitHub, Discord, etc.), two-factor authentication (TOTP, SMS), passkeys/WebAuthn support, session management, role-based access control (RBAC), rate limiting, and database adapters. Use when adding authentication to applications, implementing OAuth flows, setting up 2FA/MFA, managing user sessions, configuring authorization rules, or building secure authentication systems for web applications.
roier-seo
davila7
Technical SEO auditor and fixer. Runs Lighthouse/PageSpeed audits on websites or local dev servers, analyzes SEO/performance/accessibility scores, and automatically implements fixes for meta tags, structured data, Core Web Vitals, and accessibility issues.
auth-patterns
davepoon
This skill should be used when the user asks about "authentication in Next.js", "NextAuth", "Auth.js", "middleware auth", "protected routes", "session management", "JWT", "login flow", or needs guidance on implementing authentication and authorization in Next.js applications.
evals-context
RooCodeInc
Provides context about the Roo Code evals system structure in this monorepo. Use when tasks mention "evals", "evaluation", "eval runs", "eval exercises", or working with the evals infrastructure. Helps distinguish between the evals execution system (packages/evals, apps/web-evals) and the public website evals display page (apps/web-roo-code/src/app/evals).
dust-test
dust-tt
Step-by-step guide for writing focused, practical tests for Dust codebases following the 80/20 principle.