safe-action-better-auth — Claude Code skill: auth for safe actions
This skill wires Better Auth into next-safe-action: the middleware fetches the session, rejects unauthenticated calls and hands you a typed context.
npx skills add next-safe-action/skills --skill safe-action-better-auth -a claude-codeWhat safe-action-better-auth does
Reach for it when a Next.js project already uses next-safe-action and you are adding sign-in or permission checks to server actions. The skill walks through building an action client with the betterAuth(auth) middleware: it calls auth.api.getSession() with headers from next/headers, and when there is no session it triggers unauthorized() from next/navigation. Your action context gets { auth: { user, session } }, with types inferred from your Better Auth instance, plugin fields included.
The steps cover a Better Auth instance with nextCookies() last in the plugin array, the authInterrupts: true flag in next.config.ts, a separate client for authenticated actions, and a sample action with inputSchema. There is a section on custom authorize callbacks plus the BetterAuthContext, AuthorizeFn and BetterAuthOpts types.
Two spots where things break quietly. Skip nextCookies() and the session comes back null whenever an action tries to set cookies, so check the plugin order first. Skip the authInterrupts flag and unauthorized() throws at runtime. Also, don't refetch the session inside authorize — it arrives as authData.
What it helps with
- block unauthenticated calls to server actions
- get typed
userandsessionin the action context - make sign-in and sign-up set cookies via
nextCookies() - add a role or organization check with
authorize - drop hand-written auth middleware for the adapter
Example prompts for the agent
- Add Better Auth to my safe actions
- Set up
betterAuth(auth)with a typed context - Add an admin role check in
authorizefor this action
How to install safe-action-better-auth
1Skills CLI (Vercel)
npx skills add next-safe-action/skills --skill safe-action-better-auth -a claude-code2Manually: put the files in place
~/.claude/skills/safe-action-better-auth/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/safe-action-better-auth/
1Skills CLI (Vercel)
npx skills add next-safe-action/skills --skill safe-action-better-auth -a codex2Manually: put the files in place
.agents/skills/safe-action-better-auth/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add next-safe-action/skills --skill safe-action-better-auth -a cursor2Manually: put the files in place
.cursor/skills/safe-action-better-auth/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install next-safe-action/skills safe-action-better-auth2Manually: put the files in place
.github/skills/safe-action-better-auth/SKILL.md1Skills CLI (Vercel)
npx skills add next-safe-action/skills --skill safe-action-better-auth -a gemini-cli2Platform CLI
gemini skills install https://github.com/next-safe-action/skills --path skills/safe-action-better-authManually: put the files in place
.devin/skills/safe-action-better-auth/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add next-safe-action/skills --skill safe-action-better-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 safe-action-better-auth
How do I install safe-action-better-auth in Claude?
Run npx skills add next-safe-action/skills --skill safe-action-better-auth -a claude-code. The skill lands in ~/.claude/skills/safe-action-better-auth/SKILL.md.
What does safe-action-better-auth do?
It shows how to connect Better Auth to next-safe-action: the middleware reads the session from request headers, blocks unauthenticated calls and puts a typed auth object into the action context.
What has to be set up first?
The nextCookies() plugin last in the Better Auth plugin array and authInterrupts: true in next.config.ts. Without the first, cookies won't be set; without the second, unauthorized() throws at runtime.