cloudflare-full-stack-integration — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited cloudflare-full-stack-integration (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Production-tested patterns for React + Cloudflare Workers + Hono + Clerk authentication.
Use this skill when you need to:
Frontend (templates/frontend/):
lib/api-client.ts - Fetch wrapper with automatic token attachmentcomponents/ProtectedRoute.tsx - Auth gate pattern with loading statesBackend (templates/backend/):
middleware/cors.ts - CORS configuration for dev and productionmiddleware/auth.ts - JWT verification with Clerkroutes/api.ts - Example API routes with all patterns integratedConfig (templates/config/):
wrangler.jsonc - Complete Workers configuration with bindings.dev.vars.example - Environment variables setupvite.config.ts - Cloudflare Vite plugin configurationReferences (references/):
common-race-conditions.md - Complete guide to auth loading issuesKey Insight: The Worker and frontend run on the SAME port during development.
// ✅ CORRECT: Use relative URLs
fetch('/api/data')
// ❌ WRONG: Don't use absolute URLs or proxy
fetch('http://localhost:8787/api/data')Why: The Vite plugin runs your Worker using workerd directly in the dev server. No proxy needed!
// ✅ CORRECT ORDER
app.use('/api/*', cors())
app.post('/api/data', handler)
// ❌ WRONG ORDER - Will cause CORS errors
app.post('/api/data', handler)
app.use('/api/*', cors())Most "race conditions" are actually missing isLoaded checks:
// ❌ WRONG: Calls API before token ready
useEffect(() => {
fetch('/api/data') // 401 error!
}, [])
// ✅ CORRECT: Wait for auth to load
const { isLoaded, isSignedIn } = useSession()
useEffect(() => {
if (!isLoaded || !isSignedIn) return
fetch('/api/data') // Now token is ready
}, [isLoaded, isSignedIn])Frontend (Vite):
VITE_ prefix.env fileimport.meta.env.VITE_VARIABLE_NAMEBackend (Workers):
.dev.vars file (dev) or wrangler secrets (prod)env.VARIABLE_NAMED1 is accessed via bindings - no connection management needed:
// ✅ CORRECT: Direct access via binding
const { results } = await env.DB.prepare('SELECT * FROM users').run()
// ❌ WRONG: No need to "connect" first
const connection = await env.DB.connect() // This doesn't exist!# Create project with Cloudflare Workers + React
npm create cloudflare@latest my-app
cd my-app
# Install dependencies
npm install hono @clerk/clerk-react @clerk/backend
npm install -D @cloudflare/vite-plugin @tailwindcss/viteCopy templates/config/vite.config.ts to your project root.
Key points:
cloudflare() pluginCopy templates/config/wrangler.jsonc to your project root.
Update:
name with your app namerun_worker_first: ["/api/*"] for API routesCreate .dev.vars (gitignored):
CLERK_PUBLISHABLE_KEY=pk_test_xxxxx
CLERK_SECRET_KEY=sk_test_xxxxxCreate .env for frontend:
VITE_CLERK_PUBLISHABLE_KEY=pk_test_xxxxxCopy templates/backend/middleware/cors.ts to your backend.
Apply in your main worker file:
import { corsMiddleware } from './middleware/cors'
app.use('/api/*', (c, next) => corsMiddleware(c.env)(c, next))CRITICAL: Apply this BEFORE defining routes!
Copy templates/backend/middleware/auth.ts to your backend.
Apply to protected routes:
import { jwtAuthMiddleware } from './middleware/auth'
app.use('/api/protected/*', jwtAuthMiddleware(c.env.CLERK_SECRET_KEY))Copy templates/frontend/lib/api-client.ts to your frontend.
Use in your App component:
import { useApiClient } from '@/lib/api-client'
function App() {
useApiClient() // Set up token access
return <YourApp />
}Copy templates/frontend/components/ProtectedRoute.tsx.
Use to wrap authenticated pages:
<ProtectedRoute>
<Dashboard />
</ProtectedRoute>Copy templates/backend/routes/api.ts as a reference.
Pattern for all routes:
# Start dev server
npm run dev
# Both frontend and backend run on http://localhost:5173
# API routes: http://localhost:5173/api/*
# Frontend: http://localhost:5173/*Symptom: API calls fail with 401 even though user is signed in
Cause: API called before Clerk session is loaded
Fix: Check isLoaded and isSignedIn before API calls
const { isLoaded, isSignedIn } = useSession()
if (!isLoaded || !isSignedIn) return // Wait for authSee: references/common-race-conditions.md
Symptom: "No 'Access-Control-Allow-Origin' header" errors
Causes:
Fix:
// Apply BEFORE routes
app.use('/api/*', cors())
app.post('/api/data', handler)For production, update corsProdMiddleware with your domain.
Symptom: Variables are undefined in frontend or backend
Frontend Fix:
VITE_.env file (not .dev.vars)import.meta.env.VITE_NAMEBackend Fix:
.dev.vars for local devwrangler secret put NAME for productionenv.NAMESymptom: Database queries throw errors
Causes:
Fix:
// ✅ CORRECT: Parameterized query
await env.DB.prepare('SELECT * FROM users WHERE id = ?')
.bind(userId)
.run()
// ❌ WRONG: SQL injection risk
await env.DB.prepare(`SELECT * FROM users WHERE id = ${userId}`).run()Symptom: Backend receives requests without Authorization header
Cause: Not using apiClient or not calling useApiClient() hook
Fix:
useApiClient() in App componentapiClient.get() instead of raw fetch()// In App.tsx
import { useApiClient } from '@/lib/api-client'
function App() {
useApiClient() // MUST call this
return <YourApp />
}
// In components
import { apiClient } from '@/lib/api-client'
const data = await apiClient.get('/api/data')Before deployment, verify:
Frontend:
useApiClient() called in App component<ProtectedRoute>isLoaded before making API callsVITE_apiClient for all API callsBackend:
/api/protected/* routes.dev.vars (dev) and secrets (prod)Config:
wrangler.jsonc has correct bindingsvite.config.ts includes cloudflare() plugin.dev.vars exists and is gitignored.env exists for frontend varsrun_worker_first: ["/api/*"] in wrangler.jsoncAll packages are current stable versions:
{
"@clerk/clerk-react": "5.53.3",
"@clerk/backend": "2.19.0",
"hono": "4.10.2",
"vite": "7.1.11",
"@cloudflare/vite-plugin": "1.13.14"
}Patterns tested in:
Without this skill: ~12k tokens + 2-4 integration errors With this skill: ~4k tokens + 0 errors Savings: ~67% tokens, 100% error prevention
Remember: Most integration issues are just missing isLoaded checks or wrong middleware order. Use the templates and follow the step-by-step guide!
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.