From features
Implements Clerk authentication patterns in Astro apps: middleware for protected routes, SSR pages via Astro.locals.auth(), island components with useAuth() hooks, API routes, and static vs SSR handling.
npx claudepluginhub clerk/skills --plugin mobileThis skill is limited to using the following tools:
SDK: `@clerk/astro` v3+. Requires Astro 4.15+.
evals/evals.jsonreferences/api-routes.mdreferences/astro-react.mdreferences/island-components.mdreferences/middleware.mdreferences/ssr-pages.mdtemplates/astro-basic-auth/astro.config.mjstemplates/astro-basic-auth/package.jsontemplates/astro-basic-auth/src/layouts/Layout.astrotemplates/astro-basic-auth/src/middleware.tstemplates/astro-basic-auth/src/pages/index.astrotemplates/astro-basic-auth/tsconfig.jsonProvides patterns for Astro: islands architecture, content collections, rendering strategies (SSG/SSR/hybrid), view transitions, partial hydration, and adapters for Cloudflare/Vercel/Netlify deployment.
Provides advanced Next.js patterns for Clerk auth: middleware strategies (public/protected-first), server/client auth differences, Server Actions protection, API routes (401/403), and user-scoped caching.
Provides Clerk SDK patterns for Next.js authentication: server auth checks, client hooks, middleware protection, and user data access.
Share bugs, ideas, or general feedback.
SDK: @clerk/astro v3+. Requires Astro 4.15+.
| Task | Reference |
|---|---|
| Configure middleware | references/middleware.md |
| Protect SSR pages | references/ssr-pages.md |
| Use Clerk in island components | references/island-components.md |
| Auth in API routes | references/api-routes.md |
| Use Clerk with React in Astro | references/astro-react.md |
Astro has two rendering modes per page: SSR and static prerender. Clerk works differently in each:
Astro.locals.auth() which is populated by the middlewareexport const prerender = true) — Clerk middleware skips them; use client-side hooks in islandsuseAuth() and other hooks from @clerk/astro/reactRequest → clerkMiddleware() → SSR page → Astro.locals.auth()
↓
Island (.client) → useAuth() hook
import { defineConfig } from 'astro/config'
import clerk from '@clerk/astro'
export default defineConfig({
integrations: [clerk()],
output: 'server',
})
import { clerkMiddleware, createRouteMatcher } from '@clerk/astro/server'
const isProtectedRoute = createRouteMatcher(['/dashboard(.*)'])
export const onRequest = clerkMiddleware((auth, context, next) => {
if (isProtectedRoute(context.request) && !auth().userId) {
return auth().redirectToSignIn()
}
return next()
})
---
const { userId, orgId } = Astro.locals.auth()
if (!userId) return Astro.redirect('/sign-in')
---
<h1>Dashboard</h1>
| Symptom | Cause | Fix |
|---|---|---|
Astro.locals.auth is undefined | Missing middleware | Add clerkMiddleware to src/middleware.ts |
| Auth works in dev but not production | output: 'static' globally | Set output: 'server' or hybrid for protected pages |
| Static page has no auth | Prerendered pages skip middleware | Use export const prerender = false or move to island |
| Island not reactive to sign-in | Missing client:load directive | Add client:load to the island component |
| What | Import From |
|---|---|
clerkMiddleware, createRouteMatcher | @clerk/astro/server |
useAuth, useUser, UserButton | @clerk/astro/react |
Astro components (<SignIn>, etc.) | @clerk/astro/components |
# .env
PUBLIC_CLERK_PUBLISHABLE_KEY=pk_...
CLERK_SECRET_KEY=sk_...
Astro uses PUBLIC_ prefix for client-exposed variables (not NEXT_PUBLIC_).
clerk-setup - Initial Clerk installclerk-custom-ui - Custom flows & appearanceclerk-orgs - B2B organizations