convex-auth — Claude Code skill: auth and install
This skill adds passkey, OAuth, or password sign-in to a Convex app. Use it when auth needs to reach the server config, client hooks, and route guards.
npx skills add convex/agent-skills --skill convex-auth -a claude-codeWhat convex-auth does
The skill installs @convex-dev/auth, adds a provider in convex/auth.ts, updates convex.config.ts, and writes auth.config.ts. Passkeys are the default; OAuth or password can be selected when requested. On the client, it wires ConvexAuthProvider, a sign-in component, and route guards.
It generates an RS256 key pair with jose, produces JWT_PRIVATE_KEY and JWKS, then sets them with SITE_URL on the deployment. With pnpm, jose must also be added separately. Do not run the interactive npx @convex-dev/auth wizard: it hangs in headless or anonymous runs. Any imported shadcn/ui primitives must be added before the import. The workflow ends by checking a real sign-in round trip.
What it helps with
- add passkey sign-in to a Convex app
- switch the provider to OAuth or password
- wire
auth.config.tsinto the auth setup - generate
JWT_PRIVATE_KEYandJWKSwithout the interactive wizard - connect sign-in UI and route guards
Example prompts for the agent
- Add passkey sign-in to the current Convex app and verify a real sign-in round trip.
- Set up Google OAuth in
convex/auth.ts, writeauth.config.ts, and guard the authenticated routes. - Wire
ConvexAuthProvider, create the sign-in UI, and generate the auth keys withjosewithout using the interactive wizard.
How to install convex-auth
1Skills CLI (Vercel)
npx skills add convex/agent-skills --skill convex-auth -a claude-code2Manually: put the files in place
~/.claude/skills/convex-auth/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/convex-auth/
1Skills CLI (Vercel)
npx skills add convex/agent-skills --skill convex-auth -a codex2Manually: put the files in place
.agents/skills/convex-auth/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add convex/agent-skills --skill convex-auth -a cursor2Manually: put the files in place
.cursor/skills/convex-auth/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install convex/agent-skills convex-auth2Manually: put the files in place
.github/skills/convex-auth/SKILL.md1Skills CLI (Vercel)
npx skills add convex/agent-skills --skill convex-auth -a gemini-cli2Platform CLI
gemini skills install https://github.com/convex/agent-skills --path skills/convex-authManually: put the files in place
.devin/skills/convex-auth/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add convex/agent-skills --skill convex-auth -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
Step by step, with commands for each platform: How to install skills in Claude Code: five ways
Questions about convex-auth
How do I install convex-auth in Claude Code?
Run npx skills add convex/agent-skills --skill convex-auth -a claude-code, then run npx skills add convex/agent-skills --skill convex-auth -a claude-code again. The skill file is at ~/.claude/skills/convex-auth/SKILL.md.
What does convex-auth do?
It adds an auth provider, server and client wiring, sign-in UI, and route guards to the current Convex app. Passkeys are used by default.
Why does the setup include auth.config.ts and generated keys?
A missing or incorrect auth.config.ts leaves the app silently signed out. The skill generates JWT_PRIVATE_KEY and JWKS with jose, then sets them with SITE_URL on the deployment.
Source text
SKILL.md · Apache-2.0
---
name: convex-auth
description: "Add authentication (passkeys/OAuth) to the current Convex app, including the auth.config.ts wiring."
---
<!-- GENERATED from convex-agents content/capabilities/auth.json — do not edit by hand. -->
# Add sign-in to the app
Install and wire @convex-dev/auth for the current app: a provider (passkeys by default, or OAuth/password), the server config, the client hooks, and a sign-in UI — correctly, including the auth.config.ts that's the #1 real-world auth footgun.
## Workflow
1. Install @convex-dev/auth (pinned build) and add it to convex.config.ts. With pnpm, also `pnpm add jose` (it won't hoist otherwise); you need it for step 3.
2. Add the provider in convex/auth.ts (Passkey by default; Password or OAuth like Google on request).
3. Generate the auth keys HEADLESSLY. Do NOT run the interactive `npx @convex-dev/auth` wizard: it needs a login/TTY and hangs in non-interactive, anonymous, or CI runs (the #1 auth time-sink). Generate JWT_PRIVATE_KEY + JWKS deterministically with `jose`:
node -e 'import("jose").then(async({generateKeyPair,exportPKCS8,exportJWK})=>{const k=await generateKeyPair("RS256",{extractable:true});const priv=await exportPKCS8(k.privateKey);const pub=await exportJWK(k.publicKey);process.stdout.write(JSON.stringify({JWT_PRIVATE_KEY:priv.trimEnd().replace(/\n/g," "),JWKS:JSON.stringify({keys:[{use:"sig",...pub}]})}))})' > .auth-keys.json
Then set JWT_PRIVATE_KEY and JWKS (from .auth-keys.json) plus SITE_URL on the deployment. Prefer the Convex MCP `envSet` tool, one call per var, to avoid shell-quoting the multi-line key. CLI fallback: use the NAME=VALUE form (`npx convex env set "JWT_PRIVATE_KEY=$JWT"`), NEVER `env set JWT_PRIVATE_KEY "$JWT"` (the value starts with `-----BEGIN` and the CLI parses the leading `-` as an unknown flag). SITE_URL is the dev URL (e.g. http://localhost:3000). Delete .auth-keys.json after.
4. Write convex/auth.config.ts (the silently-always-signed-out bug lives here if it's wrong).
5. Wire the client: ConvexAuthProvider, the sign-in component, and route guards. If you import shadcn/ui primitives (button, input, textarea, label, and so on), add them first with `npx shadcn@latest add <name>`; a missing @/components/ui/* is a hard build error.
6. Verify a sign-in round-trips before declaring done.
## Rules
- Generate JWT_PRIVATE_KEY/JWKS with `jose` (extractable RS256; PKCS8 newlines to spaces; JWKS = {keys:[{use:"sig", ...publicJwk}]}). Do NOT run the interactive `npx @convex-dev/auth` wizard: it hangs headless/anonymous. Set the vars via the MCP `envSet` tool or the NAME=VALUE CLI form.
- Always write auth.config.ts: a missing/incorrect one makes the app silently always-signed-out with no error.
- Passkeys by default; only switch to password/OAuth on explicit request.
- Install any shadcn/ui primitive you import up front (`npx shadcn@latest add ...`); a missing @/components/ui/* is a hard build failure.
- Verify a real sign-in works before finishing.
© convex · Apache-2.0 · convex/agent-skills