| name | test-auth-wrapper |
| description | Expert knowledge on CLI testing with auth bypass, automated endpoint testing, and the 3 bypass methods (headers, environment, test headers). Use this skill when user asks about "test endpoint", "cli testing", "auth bypass", "curl", "automated testing", "local development", or "testing without clerk". |
| allowed-tools | Read, Bash, Grep |
Test Auth Wrapper Expert
You are an expert in testing API endpoints locally without full Clerk authentication. This skill provides knowledge about the 3 auth bypass methods and CLI testing patterns.
When To Use This Skill
This skill activates when users:
- Need to test endpoints from CLI or scripts
- Want to bypass Clerk auth for local development
- Write automated tests for API routes
- Debug endpoints without browser session
- Run scripts that call internal APIs
- Perform integration testing
Core Knowledge
The 3 Auth Bypass Methods
Bypass Resolution (from /lib/auth/get-auth-or-test.ts):
- Test Headers (Highest Priority)
- Dev Bypass Header
- Environment Bypass
- Clerk Auth (Fallback)
Method 1: Test Headers
Use Case: Automated tests, CI/CD
Headers:
x-test-user-id: User ID to impersonate
x-test-email: Email (optional)
Example:
curl http://localhost:3000/api/campaigns \
-H "x-test-user-id: user_2abc123xyz" \
-H "x-test-email: test@example.com"
Implementation:
const payload = verifyTestAuthHeaders(headerStore);
if (payload?.userId) {
return {
userId: payload.userId,
sessionId: `test_${payload.userId}`,
sessionClaims: payload.email ? { email: payload.email } : undefined,
};
}
Advantages:
- Works in any environment
- Per-request control
- No config files needed
- Easy to test different users
Disadvantages:
- Must add headers to every request
Method 2: Dev Bypass Header
Use Case: Manual CLI testing, Postman
Headers:
x-dev-auth: dev-bypass (token must match AUTH_BYPASS_TOKEN)
x-dev-user-id: User ID (optional, falls back to AUTH_BYPASS_USER_ID)
x-dev-email: Email (optional, falls back to AUTH_BYPASS_EMAIL)
Environment Variables:
AUTH_BYPASS_TOKEN=dev-bypass
AUTH_BYPASS_HEADER=x-dev-auth
AUTH_BYPASS_USER_ID=user_2abc123xyz
AUTH_BYPASS_EMAIL=dev@example.com
Example:
curl http://localhost:3000/api/campaigns \
-H "x-dev-auth: dev-bypass"
curl http://localhost:3000/api/campaigns \
-H "x-dev-auth: dev-bypass" \
-H "x-dev-user-id: user_different123"
Implementation:
const defaultBypassToken = process.env.AUTH_BYPASS_TOKEN || 'dev-bypass';
const bypassHeaderName = process.env.AUTH_BYPASS_HEADER?.toLowerCase() || 'x-dev-auth';
if (
process.env.NODE_ENV !== 'production' &&
headerStore.get(bypassHeaderName) === defaultBypassToken
) {
const userIdFromHeader = headerStore.get('x-dev-user-id') || process.env.AUTH_BYPASS_USER_ID;
return {
userId: userIdFromHeader,
sessionId: 'bypass',
sessionClaims: { }
};
}
Advantages:
- Configurable token for security
- Default user from .env
- Easy to change user per-request
- Good for Postman collections
Disadvantages:
- Requires .env setup
- Only works in non-production
Method 3: Environment Bypass
Use Case: Long dev sessions, scripts
Environment Variables:
ENABLE_AUTH_BYPASS=true
AUTH_BYPASS_USER_ID=user_2abc123xyz
AUTH_BYPASS_EMAIL=dev@example.com
Example:
curl http://localhost:3000/api/campaigns
curl -X POST http://localhost:3000/api/campaigns \
-H "Content-Type: application/json" \
-d '{"name":"Test","searchType":"instagram-reels"}'
Implementation:
const bypassEnabled = process.env.ENABLE_AUTH_BYPASS === 'true';
const bypassUserId = process.env.AUTH_BYPASS_USER_ID;
if (bypassEnabled && bypassUserId && process.env.NODE_ENV !== 'production') {
return {
userId: bypassUserId,
sessionId: 'bypass',
sessionClaims: { }
};
}
Advantages:
- No headers needed
- Fastest for dev
- Works for all requests automatically
Disadvantages:
- Can't test different users without restart
- Easy to forget it's enabled
- Must disable for Clerk testing
Common Patterns
Pattern 1: Testing Endpoint with curl
curl http://localhost:3000/api/billing/status \
-H "x-dev-auth: dev-bypass"
curl http://localhost:3000/api/billing/status \
-H "x-test-user-id: user_2abc123xyz"
curl -X POST http://localhost:3000/api/campaigns \
-H "x-dev-auth: dev-bypass" \
-H "Content-Type: application/json" \
-d '{"name":"Test Campaign","searchType":"instagram-reels","keywords":["fitness"]}'
curl -X DELETE http://localhost:3000/api/campaigns/xxx-xxx-xxx \
-H "x-dev-auth: dev-bypass"
Pattern 2: Node Script Testing
require('dotenv').config({ path: '.env.local' });
async function testEndpoint() {
const response = await fetch('http://localhost:3000/api/campaigns', {
headers: {
'x-dev-auth': 'dev-bypass',
'x-dev-user-id': 'user_2abc123xyz'
}
});
const data = await response.json();
console.log('Response:', data);
}
testEndpoint();
Run: node scripts/test-endpoint.js
Pattern 3: Automated Test Suite
import { describe, it, expect } from 'vitest';
const BASE_URL = 'http://localhost:3000';
const TEST_USER_ID = 'user_test123';
describe('Campaigns API', () => {
it('should create campaign', async () => {
const response = await fetch(`${BASE_URL}/api/campaigns`, {
method: 'POST',
headers: {
'x-test-user-id': TEST_USER_ID,
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'Test Campaign',
searchType: 'instagram-reels',
keywords: ['fitness']
})
});
expect(response.status).toBe(201);
const data = await response.json();
expect(data.success).toBe(true);
expect(data..).();
});
(, () => {
response = (, {
: ,
: {
: ,
: ,
:
},
: .({
: ,
:
})
});
(response.).();
data = response.();
(data.).();
});
});
Pattern 4: Plan Bypass (Testing Without Limits)
curl -X POST http://localhost:3000/api/campaigns \
-H "x-dev-auth: dev-bypass" \
-H "x-plan-bypass: campaigns" \
-H "Content-Type: application/json" \
-d '{"name":"Test","searchType":"instagram-reels"}'
curl -X POST http://localhost:3000/api/campaigns \
-H "x-dev-auth: dev-bypass" \
-H "x-plan-bypass: all"
PLAN_VALIDATION_BYPASS=all
Anti-Patterns (Avoid These)
Anti-Pattern 1: Hardcoding User IDs in Code
export async function POST(req: Request) {
const userId = 'user_2abc123xyz';
}
Why it's bad: Breaks production, not flexible
Do this instead:
const auth = await getAuthOrTest();
if (!auth?.userId) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
Anti-Pattern 2: Leaving Bypass Enabled in Production
if (process.env.ENABLE_AUTH_BYPASS === 'true') {
return { userId: process.env.AUTH_BYPASS_USER_ID };
}
Why it's bad: Massive security hole in production
Do this instead:
if (
process.env.ENABLE_AUTH_BYPASS === 'true' &&
process.env.NODE_ENV !== 'production'
) {
return { userId: process.env.AUTH_BYPASS_USER_ID };
}
Anti-Pattern 3: Using Bypass for Real User Actions
curl https://production.com/api/campaigns/delete-all \
-H "x-dev-auth: dev-bypass"
Why it's bad: Bypasses should only work locally
Troubleshooting Guide
Problem: Auth Bypass Not Working
Symptoms:
- Endpoint returns 401 Unauthorized
- Headers seem correct
- Environment variables set
Diagnosis:
- Check if in production (bypass disabled)
- Verify header names match exactly
- Check token matches
AUTH_BYPASS_TOKEN
- Look for typos in environment variables
Solution:
echo $NODE_ENV
cat .env.local | grep AUTH_BYPASS
curl http://localhost:3000/api/debug/whoami \
-H "x-dev-auth: dev-bypass" \
-H "x-dev-user-id: user_2abc123xyz" \
-v
Problem: Can't Test Different Users
Symptoms:
- Stuck with same user for all requests
- Want to test multi-user scenarios
Solution:
Use test headers (Method 1) instead of environment bypass:
curl http://localhost:3000/api/campaigns \
-H "x-test-user-id: user_1"
curl http://localhost:3000/api/campaigns \
-H "x-test-user-id: user_2"
Related Files
/lib/auth/get-auth-or-test.ts - Auth resolver with bypass logic
/lib/auth/testable-auth.ts - Test header verification
/app/api/debug/whoami/route.ts - Debug endpoint for testing auth
/app/api/test/auth-echo/route.ts - Echo auth context
Quick Reference
Headers:
x-test-user-id: user_xxx
x-test-email: test@example.com
x-dev-auth: dev-bypass
x-dev-user-id: user_xxx
x-dev-email: dev@example.com
x-plan-bypass: all
Environment:
ENABLE_AUTH_BYPASS=true
AUTH_BYPASS_USER_ID=user_xxx
AUTH_BYPASS_EMAIL=dev@example.com
AUTH_BYPASS_TOKEN=dev-bypass
AUTH_BYPASS_HEADER=x-dev-auth
PLAN_VALIDATION_BYPASS=all
Testing Commands:
curl http://localhost:3000/api/endpoint \
-H "x-dev-auth: dev-bypass"
curl -X POST http://localhost:3000/api/endpoint \
-H "x-dev-auth: dev-bypass" \
-H "Content-Type: application/json" \
-d '{"key":"value"}'
curl http://localhost:3000/api/endpoint \
-H "x-test-user-id: user_different"
curl http://localhost:3000/api/endpoint \
-H "x-dev-auth: dev-bypass" \
-H "x-plan-bypass: all"