clerk-nextjs-patterns

安装量: 11.9K
排名: #673

安装

npx skills add https://github.com/clerk/skills --skill clerk-nextjs-patterns
Next.js Patterns
Version
Check
package.json
for the SDK version — see
clerk
skill for the version table. Core 2 differences are noted inline with
> Core 2 ONLY (skip if current SDK):
callouts.
For basic setup, see
clerk-setup
skill.
What Do You Need?
Task
Reference
Server vs client auth (
auth()
vs hooks)
references/server-vs-client.md
Configure middleware (public-first vs protected-first)
references/middleware-strategies.md
Protect Server Actions
references/server-actions.md
API route auth (401 vs 403)
references/api-routes.md
Cache auth data (user-scoped caching)
references/caching-auth.md
References
Reference
Description
references/server-vs-client.md
await auth()
vs hooks
references/middleware-strategies.md
Public-first vs protected-first,
proxy.ts
(Next.js <=15:
middleware.ts
)
references/server-actions.md
Protect mutations
references/api-routes.md
401 vs 403
references/caching-auth.md
User-scoped caching
Mental Model
Server vs Client = different auth APIs:
Server
:
await auth()
from
@clerk/nextjs/server
(async!)
Client
:
useAuth()
hook from
@clerk/nextjs
(sync)
Never mix them. Server Components use server imports, Client Components use hooks.
Key properties from
auth()
:
isAuthenticated
— boolean, replaces the
!!userId
pattern
sessionStatus
'active'
|
'pending'
, for detecting incomplete session tasks
userId
,
orgId
,
orgSlug
,
has()
,
protect()
— unchanged
Core 2 ONLY (skip if current SDK):
isAuthenticated
and
sessionStatus
are not available. Check
!!userId
instead.
Minimal Pattern
// Server Component
import
{
auth
}
from
'@clerk/nextjs/server'
export
default
async
function
Page
(
)
{
const
{
isAuthenticated
,
userId
}
=
await
auth
(
)
// MUST await!
if
(
!
isAuthenticated
)
return
<
p
>
Not signed
in
<
/
p
>
return
<
p
>
Hello
{
userId
}
<
/
p
>
}
Core 2 ONLY (skip if current SDK):
isAuthenticated
is not available. Use
if (!userId)
instead.
Conditional Rendering with
For client-side conditional rendering based on auth state:
import
{
Show
}
from
'@clerk/nextjs'
<
Show
when
=
"
signed-in
"
fallback
=
{
<
p
>
Please sign in
</
p
>
}
>
<
Dashboard
/>
</
Show
>
Core 2 ONLY (skip if current SDK):
Use
and
components instead of
. See
clerk-custom-ui
skill,
core-3/show-component.md
for the full migration table.
Common Pitfalls
Symptom
Cause
Fix
undefined
userId in Server Component
Missing
await
await auth()
not
auth()
Auth not working on API routes
Missing matcher
Add `'/(api
Cache returns wrong user's data
Missing userId in key
Include
userId
in
unstable_cache
key
Mutations bypass auth
Unprotected Server Action
Check
auth()
at start of action
Wrong HTTP error code
Confused 401/403
401 = not signed in, 403 = no permission
Session Tokens & Custom JWTs
getToken() for external APIs
Pass a custom JWT to third-party services (Hasura, Supabase, etc.) using JWT templates defined in the Clerk dashboard.
Server-side (Server Component or Route Handler)
:
import
{
auth
}
from
'@clerk/nextjs/server'
export
default
async
function
Page
(
)
{
const
{
getToken
}
=
await
auth
(
)
const
token
=
await
getToken
(
{
template
:
'hasura'
}
)
if
(
!
token
)
return
<
p
>
Not authenticated
<
/
p
>
const
res
=
await
fetch
(
'https://api.example.com/graphql'
,
{
headers
:
{
Authorization
:
`
Bearer
${
token
}
`
}
,
}
)
const
data
=
await
res
.
json
(
)
return
<
pre
>
{
JSON
.
stringify
(
data
)
}
<
/
pre
>
}
Client-side (Client Component)
:
'use client'
import
{
useAuth
}
from
'@clerk/nextjs'
export
function
DataFetcher
(
)
{
const
{
getToken
}
=
useAuth
(
)
async
function
fetchData
(
)
{
const
token
=
await
getToken
(
{
template
:
'supabase'
}
)
if
(
!
token
)
return
const
res
=
await
fetch
(
'https://api.example.com/data'
,
{
headers
:
{
Authorization
:
`
Bearer
${
token
}
`
}
,
}
)
return
res
.
json
(
)
}
return
<
button onClick
=
{
fetchData
}
>
Fetch
<
/
button
>
}
getToken()
returns
null
when the user is not authenticated — always null-check before use.
useSession() for session data
Access session metadata in client components:
'use client'
import
{
useSession
}
from
'@clerk/nextjs'
export
function
SessionInfo
(
)
{
const
{
session
}
=
useSession
(
)
if
(
!
session
)
return
null
return
(
<
p
>
Session
{
session
.
id
}
— last active
:
{
session
.
lastActiveAt
.
toISOString
(
)
}
<
/
p
>
)
}
Manual JWT verification (no Clerk middleware)
For standalone API servers that receive Clerk session tokens from the
Authorization
header or the
__session
cookie (same-origin).
Using
@clerk/backend
verifyToken
(recommended):
import
{
verifyToken
}
from
'@clerk/backend'
const
token
=
req
.
headers
.
authorization
?.
replace
(
'Bearer '
,
''
)
if
(
!
token
)
return
res
.
status
(
401
)
.
json
(
{
error
:
'No token'
}
)
try
{
const
claims
=
await
verifyToken
(
token
,
{
jwtKey
:
process
.
env
.
CLERK_JWT_KEY
,
}
)
// claims.sub = userId
}
catch
{
return
res
.
status
(
401
)
.
json
(
{
error
:
'Invalid token'
}
)
}
Using
jsonwebtoken
(when you can't use
@clerk/backend
):
import
jwt
from
'jsonwebtoken'
const
publicKey
=
process
.
env
.
CLERK_PEM_PUBLIC_KEY
!
.
replace
(
/
\
n
/
g
,
'\n'
)
const
token
=
req
.
headers
.
authorization
?.
replace
(
'Bearer '
,
''
)
if
(
!
token
)
return
res
.
status
(
401
)
.
json
(
{
error
:
'No token'
}
)
try
{
const
claims
=
jwt
.
verify
(
token
,
publicKey
,
{
algorithms
:
[
'RS256'
]
}
)
as
jwt
.
JwtPayload
// Manually check exp and nbf (jsonwebtoken does this automatically, but verify azp if needed)
// claims.sub = userId
}
catch
{
return
res
.
status
(
401
)
.
json
(
{
error
:
'Invalid or expired token'
}
)
}
Token sources:
Same-origin requests
:
__session
cookie (Clerk sets this automatically)
Cross-origin / mobile / API-to-API
:
Authorization: Bearer
header
CRITICAL
Always check exp and nbf claims. verifyToken from @clerk/backend handles this automatically; with raw jsonwebtoken , set ignoreExpiration: false (default) and ensure clockTolerance is minimal. See Also clerk-setup clerk-orgs Docs Next.js SDK
返回排行榜