| name | clerk |
| description | [Applies to: **/*] This guide establishes definitive best practices for integrating Clerk, focusing on robust security, efficient session management, and secure token handling in line with modern OAuth 2.0 (RFC 9700) and JWT (RFC 8725) standards. |
| source | cursor_mdc |
Clerk Best Practices
Integrating Clerk requires a security-first mindset. Authentication is a primary attack surface; therefore, all Clerk integrations MUST adhere to the strictest security standards. This guide provides actionable, opinionated best practices to ensure your application's identity layer is robust and future-proof.
1. Security Best Practices
1.1. Enforce Authorization Code Flow with PKCE
NEVER use the implicit grant flow. RFC 9700 explicitly deprecates it due to inherent security weaknesses. Always use the Authorization Code Flow with Proof Key for Code Exchange (PKCE). Clerk's client-side SDKs handle PKCE automatically when correctly configured.
❌ BAD: Relying on deprecated flows (e.g., implicit grant)
✅ GOOD: Utilize Clerk's Authorization Code Flow with PKCE (default for modern SDKs)
import { ClerkProvider } from '@clerk/nextjs';
function MyApp({ Component, pageProps }) {
return (
<ClerkProvider {...pageProps}>
<Component {...pageProps} />
</ClerkProvider>
);
}
1.2. Centralize Authentication Logic
All authentication and authorization checks MUST occur server-side and be handled by a centralized, security-vetted library (Clerk's backend SDKs). Never perform critical authentication decisions solely on the client.
❌ BAD: Client-side authorization decisions
if (clerk.user.publicMetadata.role === 'admin') {
}
✅ GOOD: Server-side authorization with Clerk's backend SDKs
import { getAuth } from '@clerk/nextjs/server';
import { NextApiRequest, NextApiResponse } from 'next';
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const { userId, orgRole } = getAuth(req);
if (!userId) {
return res.status(401).json({ error: 'Unauthorized' });
}
if (orgRole !== 'admin') {
return res.status(403).json({ error: 'Forbidden' });
}
res.status(200).json({ message: 'Welcome, admin!' });
}
1.3. Securely Store API Keys and Secrets
API keys, client secrets, and Clerk private keys MUST NEVER be hardcoded or stored directly in source code or configuration files. Use a managed Secrets Manager (e.g., AWS Secrets Manager, Azure Key Vault, HashiCorp Vault) and reference them at runtime via environment variables.
❌ BAD: Hardcoding secrets
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY='pk_test_YOUR_PUBLISHABLE_KEY'
CLERK_SECRET_KEY='sk_test_YOUR_SECRET_KEY_HARDCODED'
const clerkSecretKey = 'sk_test_YOUR_SECRET_KEY_HARDCODED';
✅ GOOD: Using environment variables and a Secrets Manager
CLERK_SECRET_KEY=${CLERK_SECRET_KEY_FROM_SECRETS_MANAGER}
const clerkSecretKey = process.env.CLERK_SECRET_KEY;
if (!clerkSecretKey) {
throw new Error('CLERK_SECRET_KEY is not set.');
}
1.4. Enforce HTTPS Everywhere
All communication involving authentication credentials or sensitive data MUST occur over HTTPS. This is non-negotiable. Configure your application and infrastructure to redirect all HTTP traffic to HTTPS.
❌ BAD: Allowing HTTP connections
http://your-app.com/login // Insecure
✅ GOOD: Requiring HTTPS
https://your-app.com/login // Secure
1.5. Implement Strong Password Policies and MFA
Leverage Clerk's robust password policy configuration to enforce NIST SP 800-63B guidelines:
- Minimum length: 8 characters with MFA, 15 without MFA.
- Maximum length: At least 64 characters (allow passphrases).
- Allow all characters (unicode, whitespace).
- Block common/breached passwords (Clerk integrates with services like HaveIBeenPwned).
- Enable Multi-Factor Authentication (MFA) for all users, especially for high-risk actions or sensitive accounts.
❌ BAD: Weak password policy
✅ GOOD: Robust password policy and MFA
1.6. Validate JWTs Rigorously
When handling Clerk's JWT-based sessions (e.g., in custom backend services), always validate the token's signature, audience (aud), issuer (iss), and expiration (exp). Use strong signing algorithms (RS256 or ES256). Clerk's backend SDKs handle this automatically; avoid manual JWT parsing and validation unless absolutely necessary and with extreme caution.
❌ BAD: Trusting JWTs without full validation
const token = req.headers.authorization?.split(' ')[1];
✅ GOOD: Using Clerk's verified session/token validation
import { ClerkExpressWithAuth } from '@clerk/clerk-sdk-node';
app.use(
ClerkExpressWithAuth({
jwtKey: process.env.CLERK_JWT_VERIFICATION_KEY,
}),
(req, res, next) => {
if (!req.auth.userId) {
return res.status(401).json({ error: 'Unauthorized' });
}
next();
}
);
2. Session Management and Token Handling
2.1. Enforce Short-Lived Access Tokens
Configure Clerk sessions to use short-lived access tokens. This minimizes the window of opportunity for token compromise. Refresh tokens should be used to obtain new access tokens.
❌ BAD: Long-lived access tokens
✅ GOOD: Short-lived access tokens
2.2. Keep Clerk SDKs Up-to-Date
Regularly update your Clerk client and server SDKs to the latest stable versions. This ensures you benefit from security patches, performance improvements, and adherence to the latest best practices. As of early 2025, the CDN release is 5.62.0.
❌ BAD: Sticking to old SDK versions
"dependencies": {
"@clerk/nextjs": "^4.x.x",
}
✅ GOOD: Updating Clerk SDKs regularly
"dependencies": {
"@clerk/nextjs": "^5.x.x",
}
3. Code Organization and Vulnerability Prevention
3.1. Isolate Clerk Initialization
Initialize Clerk at the highest possible level in your application (e.g., _app.js in Next.js, main.tsx in React). This ensures consistent behavior and avoids re-initialization issues.
❌ BAD: Multiple Clerk initializations or conditional loading
✅ GOOD: Single, top-level Clerk initialization
import { ClerkProvider } from '@clerk/nextjs';
import type { AppProps } from 'next/app';
function MyApp({ Component, pageProps }: AppProps) {
return (
<ClerkProvider {...pageProps}>
<Component {...pageProps} />
</ClerkProvider>
);
}
export default MyApp;
3.2. Implement Automated Security Scans and Code Reviews
Integrate static analysis tools, linters, and dependency scanners into your CI/CD pipeline. Require mandatory code reviews for any changes touching authentication flows, Clerk integration, or security-sensitive areas.
❌ BAD: Manual, ad-hoc security checks
// Relying solely on manual testing for security vulnerabilities.
✅ GOOD: Automated and human-verified security
name: CI/CD Pipeline
jobs:
security-scan:
steps:
- uses: actions/checkout@v3
- name: Run ESLint
run: npm run lint
- name: Run Snyk/Dependabot
run: snyk test