Create your first authenticated request with Clerk. Use when making initial API calls, testing authentication, or verifying Clerk integration works correctly. Trigger with phrases like "clerk hello world", "first clerk request", "test clerk auth", "verify clerk setup".
80
77%
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Passed
No known issues
Optimize this skill with Tessl
npx tessl skill review --optimize ./plugins/saas-packs/clerk-pack/skills/clerk-hello-world/SKILL.mdMake your first authenticated requests using Clerk across server components, client components, API routes, and server actions. Validates your Clerk integration end-to-end.
clerk-install-auth completed)NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY, CLERK_SECRET_KEY)// 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.
// 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(),
})
}'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>
)
}// 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>
)
}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 | 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 |
auth() over currentUser() in hot paths to avoid Backend API rate limitscurrentUser() calls with React's cache() function across server components in the same request@clerk/backend or @clerk/expressProceed to clerk-local-dev-loop for local development workflow setup.
3a2d27d
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.