This guide explains how to configure Clerk's session token to include ManagerOS-specific data (organization ID, user ID, etc.) in the session claims.
By default, Clerk's session tokens only include basic user information. To include ManagerOS-specific data like organizationId, managerOSUserId, personId, etc., you need to:
- Customize the Session Token in Clerk Dashboard (required for
auth().sessionClaims) - Use the
syncUserDataToClerk()function to populate user metadata - Access the data via
auth()session claims
Clerk has two different concepts:
- Session Token (used by
auth()): This is what's stored in cookies and used for authentication. Custom claims must be added via "Customize session token" in the Sessions page. This is what affectsauth().sessionClaims. - JWT Templates (used by
getToken()): These are used for backend API requests, not for session tokens.
For auth().sessionClaims to work, you MUST customize the Session Token, not just create a JWT Template.
- Go to your Clerk Dashboard
- Navigate to Sessions in the sidebar
- Scroll down to Customize session token section
- Click Edit or Add claims in the Claims editor
- Add the following custom claims:
{
"managerOSUserId": "{{user.public_metadata.managerOSUserId}}",
"organizationId": "{{user.public_metadata.organizationId}}",
"organizationName": "{{user.public_metadata.organizationName}}",
"organizationSlug": "{{user.public_metadata.organizationSlug}}",
"personId": "{{user.public_metadata.personId}}",
"role": "{{user.public_metadata.role}}"
}Important:
- Make sure to use
public_metadata(with underscore) - this is Clerk's syntax for accessing public metadata. - The session token has a size limit (~1.2KB for custom claims after default claims), so keep claims small.
- Click Save to apply the changes
If you need custom claims in JWT tokens for API calls (using getToken()), you can also create a JWT Template:
- Go to JWT Templates in the sidebar
- Click New template or edit the default template
- Add the same claims as above
- Use
getToken({ template: 'template-name' })to get the token with custom claims
Note: JWT Templates do NOT affect auth().sessionClaims - they're only for tokens retrieved via getToken().
The system automatically syncs user data to Clerk's public metadata when:
- A user is created (via webhook)
- A user is updated (via webhook)
- A user is linked to an existing account (via
getCurrentUser())
Once configured, you can access the data in two ways:
import { getCurrentUser } from '@/lib/auth-utils'
// This will automatically use session claims if available, or fall back to database
const user = await getCurrentUser()
console.log(user.organizationId) // Available without database lookup!import { auth } from '@clerk/nextjs/server'
const { sessionClaims } = await auth()
const managerOSUserId = sessionClaims.managerOSUserId as string
const organizationId = sessionClaims.organizationId as string | nullIf you need to manually sync user data (e.g., after organization changes), use:
import { syncUserDataToClerk } from '@/lib/clerk'
// After user joins/leaves organization
await syncUserDataToClerk(clerkUserId)- Performance: No database lookup needed - data is in the JWT token
- Availability: Data is available in middleware and all server components
- Consistency: Data is synced automatically via webhooks
- Security: Data is signed in the JWT token
- The Session Token must be customized in Clerk Dashboard (Sessions → Customize session token) for this to work
- User metadata is synced automatically, but you may need to sign out/in for changes to appear in the token
- If session claims are not available, the system falls back to database lookup
- Public metadata is readable on both frontend and backend, but only writable from backend
- Session token size is limited to ~4KB total (including default claims), so custom claims should be kept small
- Verify the Session Token is customized in Clerk Dashboard (Sessions → Customize session token)
⚠️ Important: Creating a JWT Template alone is NOT enough - you must customize the Session Token
- Check that
syncUserDataToClerk()has been called for the user - User may need to sign out and sign back in to get a new token with custom claims
- Check Clerk Dashboard → Users → [User] → Metadata to verify data is synced to public metadata
- Check the browser console - the
console.log(sessionClaims)ingetCurrentUser()will show what claims are available
- Call
syncUserDataToClerk(clerkUserId)after any user data changes - The webhook handlers automatically sync on user updates
- Users will get updated data on their next token refresh