Authentication integration patterns for Clerk with Astro, Playwright E2E testing, and CI/CD workflows.
/plugin marketplace add wrsmith108/clerk-claude-skill/plugin install wrsmith108-clerk@wrsmith108/clerk-claude-skillThis skill inherits all available tools. When active, it can use any tool Claude has access to.
scripts/setup-test-users.tsAuthentication integration patterns for Clerk with Astro, Playwright E2E testing, and CI/CD workflows.
// Use window.Clerk directly for client-side auth checks
function checkAuth() {
if (window.Clerk?.loaded && !window.Clerk.user) {
window.Clerk.redirectToSignIn({ redirectUrl: window.location.href });
}
}
// Poll for Clerk to load
const interval = setInterval(() => {
if (window.Clerk?.loaded) {
clearInterval(interval);
checkAuth();
}
}, 100);
// API routes needing locals.auth MUST set prerender = false
export const prerender = false;
import type { APIRoute } from 'astro';
export const GET: APIRoute = async ({ locals }) => {
const { userId } = locals.auth();
if (!userId) {
return new Response('Unauthorized', { status: 401 });
}
// ... handle authenticated request
};
| Variable | Purpose | Required |
|---|---|---|
PUBLIC_CLERK_PUBLISHABLE_KEY | Frontend Clerk initialization | Yes |
CLERK_SECRET_KEY | Backend API calls | Yes |
CLERK_WEBHOOK_SECRET | Webhook signature verification | For webhooks |
CLERK_PUBLISHABLE_KEY | @clerk/testing (no PUBLIC_ prefix) | For E2E tests |
npm install --save-dev @clerk/testing
import { clerkSetup, clerk } from '@clerk/testing/playwright';
import { chromium } from '@playwright/test';
export default async function globalSetup() {
// Initialize Clerk testing utilities
await clerkSetup();
const browser = await chromium.launch();
const page = await browser.newPage();
// Navigate first (Clerk needs a page context)
await page.goto('/');
// Programmatic sign-in (no UI interaction)
await clerk.signIn({
page,
signInParams: {
strategy: 'password',
identifier: process.env.TEST_USER_EMAIL,
password: process.env.TEST_USER_PASSWORD,
},
});
// Navigate to trigger session recognition
await page.goto('/');
// Save storage state for test reuse
await page.context().storageState({ path: 'tests/.auth/user.json' });
await browser.close();
}
Environment variable naming: @clerk/testing requires CLERK_PUBLISHABLE_KEY (not PUBLIC_CLERK_PUBLISHABLE_KEY)
Password auth required: Test users must have password authentication enabled in Clerk dashboard (OAuth-only users won't work)
Navigate after sign-in: clerk.signIn() sets up the session but doesn't navigate. Call page.goto() after to capture authenticated state.
Session storage: Save storageState to reuse sessions across tests for faster execution.
Use the Clerk Backend API to create or update test users with password auth:
import { createClerkClient } from '@clerk/backend';
const clerkClient = createClerkClient({
secretKey: process.env.CLERK_SECRET_KEY,
});
async function createOrUpdateUser(email: string, password: string) {
// Check if user exists
const users = await clerkClient.users.getUserList({
emailAddress: [email],
});
if (users.data[0]) {
// Update password for existing user
await clerkClient.users.updateUser(users.data[0].id, { password });
} else {
// Create new user with password
await clerkClient.users.createUser({
emailAddress: [email],
password,
skipPasswordChecks: true,
});
}
}
steps:
- name: Install dependencies
run: npm ci
- name: Setup test users in Clerk
env:
CLERK_SECRET_KEY: ${{ secrets.CLERK_SECRET_KEY }}
TEST_USER_EMAIL: ${{ secrets.TEST_USER_EMAIL }}
TEST_USER_PASSWORD: ${{ secrets.TEST_USER_PASSWORD }}
run: npm run test:setup-users
- name: Seed test database
run: npm run db:seed:test
- name: Build application
run: npm run build
- name: Run E2E tests
env:
CLERK_PUBLISHABLE_KEY: ${{ secrets.CLERK_PUBLISHABLE_KEY }}
CLERK_SECRET_KEY: ${{ secrets.CLERK_SECRET_KEY }}
run: npm run test:e2e
| Event | Use Case |
|---|---|
user.created | Auto-create member record in database |
user.updated | Sync profile changes |
user.deleted | Remove member record |
session.created | Track login activity |
import { Webhook } from 'svix';
import type { WebhookEvent } from '@clerk/backend';
export const POST: APIRoute = async ({ request }) => {
const payload = await request.text();
const headers = {
'svix-id': request.headers.get('svix-id')!,
'svix-timestamp': request.headers.get('svix-timestamp')!,
'svix-signature': request.headers.get('svix-signature')!,
};
const wh = new Webhook(process.env.CLERK_WEBHOOK_SECRET!);
const event = wh.verify(payload, headers) as WebhookEvent;
switch (event.type) {
case 'user.created':
// Create member in database
break;
case 'user.updated':
// Update member profile
break;
case 'user.deleted':
// Remove member
break;
}
return new Response('OK', { status: 200 });
};
Use Clerk's testing tokens to bypass bot detection:
import { clerkSetup } from '@clerk/testing/playwright';
// clerkSetup() automatically handles testing tokens
await clerkSetup();
Symptom: After entering email/password, page redirects to GitHub/Google OAuth.
Cause: User account is OAuth-only, no password set.
Solution: Use scripts/setup-test-users.ts to provision users with password auth via Backend API.
Symptom: User appears logged out after navigation.
Cause: Storage state not saved or loaded correctly.
Solution:
await context.storageState({ path: 'auth.json' })browser.newContext({ storageState: 'auth.json' })Symptom: @clerk/testing throws "CLERK_PUBLISHABLE_KEY required"
Cause: Using PUBLIC_CLERK_PUBLISHABLE_KEY instead of CLERK_PUBLISHABLE_KEY
Solution: Set both in CI environment:
env:
PUBLIC_CLERK_PUBLISHABLE_KEY: ${{ secrets.CLERK_KEY }}
CLERK_PUBLISHABLE_KEY: ${{ secrets.CLERK_KEY }}
Creating algorithmic art using p5.js with seeded randomness and interactive parameter exploration. Use this when users request creating art using code, generative art, algorithmic art, flow fields, or particle systems. Create original algorithmic art rather than copying existing artists' work to avoid copyright violations.
Applies Anthropic's official brand colors and typography to any sort of artifact that may benefit from having Anthropic's look-and-feel. Use it when brand colors or style guidelines, visual formatting, or company design standards apply.
Create beautiful visual art in .png and .pdf documents using design philosophy. You should use this skill when the user asks to create a poster, piece of art, design, or other static piece. Create original visual designs, never copying existing artists' work to avoid copyright violations.