| name | session-management |
| description | Clerk session handling, JWT verification, token management, and multi-session workflows. Use when implementing session validation, JWT claims customization, token refresh patterns, session lifecycle management, or when user mentions session errors, authentication tokens, JWT verification, multi-device sessions, or session security. |
| allowed-tools | Read, Grep, Glob, Bash |
Session Management
Purpose: Autonomously configure, validate, and troubleshoot Clerk session handling, JWT verification, and token management.
Activation Triggers:
- Session validation failures
- JWT verification errors
- Token expiration issues
- Multi-session conflicts
- Custom claims configuration
- Session refresh problems
- Authentication middleware setup
- Session security audits
Key Resources:
scripts/configure-sessions.sh - Session configuration helper
scripts/setup-jwt.sh - JWT template setup and validation
scripts/test-sessions.sh - Session testing and verification
templates/session-config.ts - Session configuration patterns
templates/jwt-verification.ts - JWT verification middleware
templates/custom-claims.ts - Custom JWT claims setup
templates/session-types.ts - TypeScript type definitions
examples/multi-session.tsx - Multi-session management
examples/session-refresh.ts - Session refresh patterns
examples/session-debugging.ts - Debugging utilities
Session Configuration Workflow
1. Configure Session Settings
./scripts/configure-sessions.sh
What it configures:
- ✅ Session duration and expiration
- ✅ Multi-session behavior (allow/restrict)
- ✅ Token refresh intervals
- ✅ Activity-based session extension
- ✅ Cookie security attributes (SameSite, Secure, HttpOnly)
2. Setup JWT Templates
./scripts/setup-jwt.sh <template-name>
./scripts/setup-jwt.sh default
./scripts/setup-jwt.sh hasura
./scripts/setup-jwt.sh supabase
./scripts/setup-jwt.sh custom
Configures:
- Session ID and user ID claims
- Organization membership
- Role and permission claims
- Custom metadata fields
- Database integration claims (Hasura, Supabase)
3. Test Session Validation
./scripts/test-sessions.sh <test-type>
Session Management Patterns
Backend Session Verification
Next.js App Router:
import { auth } from '@clerk/nextjs/server';
export async function GET() {
const { userId, sessionId, sessionClaims } = await auth();
if (!userId) {
return Response.json({ error: 'Unauthorized' }, { status: 401 });
}
const userRole = sessionClaims?.role;
const orgId = sessionClaims?.org_id;
return Response.json({ userId, role: userRole });
}
Middleware Pattern:
import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server';
const isProtectedRoute = createRouteMatcher(['/dashboard(.*)']);
export default clerkMiddleware((auth, req) => {
if (isProtectedRoute(req)) {
auth().protect();
}
});
Frontend Session Access
React/Next.js:
import { useAuth, useSession } from '@clerk/nextjs';
function Component() {
const { userId, sessionId } = useAuth();
const { session } = useSession();
const lastActiveAt = session?.lastActiveAt;
const expireAt = session?.expireAt;
const handleRefresh = () => session?.touch();
return (
<div>
<p>Session ID: {sessionId}</p>
<p>Expires: {expireAt?.toLocaleString()}</p>
</div>
);
}
Multi-Session Handling
Enable multi-session mode:
import { useClerk } from '@clerk/nextjs';
function SessionSwitcher() {
const { client } = useClerk();
const sessions = client?.sessions || [];
const switchSession = async (sessionId: string) => {
await client?.setActiveSession(sessionId);
};
const signOutSession = async (sessionId: string) => {
const session = client?.sessions.find(s => s.id === sessionId);
await session?.remove();
};
return ();
}
JWT Verification (Backend)
Manual verification:
import { verifyToken } from '@clerk/backend';
async function verifySessionToken(token: string) {
try {
const payload = await verifyToken(token, {
secretKey: process.env.CLERK_SECRET_KEY!,
authorizedParties: ['https://app.example.com'],
});
return {
valid: true,
userId: payload.sub,
sessionId: payload.sid,
claims: payload,
};
} catch (error) {
return { valid: false, error: error.message };
}
}
Custom Claims Configuration
Dashboard setup:
- Navigate to Clerk Dashboard → JWT Templates
- Create/edit template
- Add custom claims in JSON format:
{
"metadata": "{{user.public_metadata}}",
"role": "{{user.public_metadata.role}}",
"org_id": "{{org.id}}",
"org_role": "{{org_membership.role}}",
"permissions": "{{org_membership.permissions}}"
}
Access in code:
import { auth } from '@clerk/nextjs/server';
const { sessionClaims } = await auth();
const role = sessionClaims?.role as string;
const orgId = sessionClaims?.org_id as string;
const permissions = sessionClaims?.permissions as string[];
Session Refresh Patterns
Automatic Refresh
Client-side auto-refresh:
import { useSession } from '@clerk/nextjs';
import { useEffect } from 'react';
function useSessionRefresh() {
const { session } = useSession();
useEffect(() => {
if (!session) return;
const expiresAt = session.expireAt?.getTime() || 0;
const refreshAt = expiresAt - (5 * 60 * 1000);
const now = Date.now();
if (refreshAt > now) {
const timeout = setTimeout(() => {
session.touch();
}, refreshAt - now);
return () => clearTimeout(timeout);
}
}, [session]);
}
Manual Session Extension
import { useSession } from '@clerk/nextjs';
function Component() {
const { session } = useSession();
const extendSession = async () => {
await session?.touch();
};
return <button onClick={extendSession}>Stay Logged In</button>;
}
Security Best Practices
Session Configuration
Recommended settings:
- Session lifetime: 7 days (default), 30 days (maximum)
- Refresh window: Last 10% of session lifetime
- Multi-session: Enabled for consumer apps, restricted for enterprise
- Secure cookies: Always enable in production
- SameSite: 'lax' (most apps), 'strict' (high security)
JWT Security
Verification checklist:
- ✅ Always verify JWT signature
- ✅ Validate expiration (
exp claim)
- ✅ Check issuer (
iss claim matches Clerk)
- ✅ Verify audience (
aud if using multiple apps)
- ✅ Validate authorized parties for multi-domain
- ✅ Never trust client-provided tokens without verification
Session Storage
Frontend:
- Clerk automatically manages session tokens
- Never store session tokens in localStorage
- Cookies are HttpOnly and Secure in production
Backend:
- Validate session on every protected request
- Cache validation results with short TTL (< 1 min)
- Invalidate cache on user metadata changes
Common Issues & Fixes
Session Not Persisting
Problem: User logged out on page refresh
Solutions:
./scripts/test-sessions.sh basic
JWT Verification Failure
Problem: verifyToken throws error
Diagnosis:
./scripts/test-sessions.sh jwt-verify
Custom Claims Not Available
Problem: Custom claims undefined in sessionClaims
Fix:
./scripts/setup-jwt.sh custom
Multi-Session Conflicts
Problem: Wrong session active after sign-in
Solutions:
await clerk.setActiveSession(sessionId);
Resources
Scripts: All scripts in scripts/ directory handle:
- Session configuration validation
- JWT template setup and testing
- Session flow verification
- Error diagnosis and fixes
Templates: templates/ contains production-ready code for:
- Session configuration objects
- JWT verification middleware
- Custom claims type definitions
- Session refresh utilities
Examples: examples/ demonstrates:
- Multi-session UI components
- Session refresh strategies
- Protected route patterns
- Session debugging helpers
Security Compliance
CRITICAL: This skill follows strict security rules:
- All code examples use placeholder API keys only
- No real secrets or credentials in templates
- Environment variable references throughout
.gitignore protection documented in all setup scripts
Supported Frameworks: Next.js (App Router, Pages Router), React, Express, Fastify, Remix
Clerk SDK Version: @clerk/nextjs 5+, @clerk/backend 1+
Version: 1.0.0