AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Dev Auth

skill-christopherlouet-claude-base-dev-auth · by christopherlouet

Modern web auth implementation (better-auth, Lucia, NextAuth/Auth.js, Clerk, Supabase Auth). Trigger when the user wants to add login, signup, sessions, OAuth, magic links, 2FA, or when existing auth code is detected to audit or migrate.

No reviews yet
0 installs
37 views
0.0% view→install

Install

$ agentstack add skill-christopherlouet-claude-base-dev-auth

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets Used
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-christopherlouet-claude-base-dev-auth)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
2mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Dev Auth? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Modern Web Auth

Choosing your auth stack

| Solution | When to choose | Avoid when | |----------|--------------|----------------| | better-auth | Total control, TS-first, extensible (plugins), native 2FA/passkeys | Project < 1 week MVP | | Lucia v3+ | Minimalist approach, source-available code, you control everything | No time for plumbing | | NextAuth/Auth.js | Next.js ecosystem, easy OAuth, lots of adapters | Need fine control over sessions | | Clerk | Fast MVP, pre-built UI, paid SaaS | Limited budget, sovereign data control | | Supabase Auth | Already on Supabase, RLS for authorization | Non-Postgres stack, complex custom auth | | Auth0 / Okta | Enterprise, SAML/SCIM compliance | Indie apps, high cost |

IMPORTANT: Never roll your own auth (homemade JWT, custom password hashing). Use a maintained lib.

better-auth (recommended 2026)

Framework-agnostic (Next, Remix, SvelteKit, Nuxt, vanilla). TypeScript-first.

Install

npm install better-auth

Minimal setup (Next.js)

// lib/auth.ts
import { betterAuth } from "better-auth";
import { Pool } from "pg";

export const auth = betterAuth({
  database: new Pool({ connectionString: process.env.DATABASE_URL }),
  emailAndPassword: { enabled: true },
  socialProviders: {
    github: {
      clientId: process.env.GITHUB_CLIENT_ID!,
      clientSecret: process.env.GITHUB_CLIENT_SECRET!,
    },
  },
});
// app/api/auth/[...all]/route.ts
import { auth } from "@/lib/auth";
import { toNextJsHandler } from "better-auth/next-js";

export const { GET, POST } = toNextJsHandler(auth);

Client

// lib/auth-client.ts
import { createAuthClient } from "better-auth/react";

export const authClient = createAuthClient();

// Usage
const { data: session } = authClient.useSession();
await authClient.signIn.email({ email, password });
await authClient.signUp.email({ email, password, name });
await authClient.signOut();

Useful plugins

import { twoFactor, magicLink, passkey } from "better-auth/plugins";

betterAuth({
  plugins: [
    twoFactor(),                              // TOTP
    magicLink({ sendMagicLink: ... }),        // Email magic link
    passkey(),                                // WebAuthn/passkeys
  ],
});

Lucia v3+ (if you need minimalism)

Since v3, Lucia ships source-available (you copy the code, not a package). Approach similar to shadcn/ui for auth.

npx create-lucia@latest

You get auth.ts, session.ts copied into your codebase. You modify them as needed.

NextAuth / Auth.js

npm install next-auth@beta
// auth.ts
import NextAuth from "next-auth";
import GitHub from "next-auth/providers/github";

export const { handlers, signIn, signOut, auth } = NextAuth({
  providers: [GitHub],
});
// app/api/auth/[...nextauth]/route.ts
export { GET, POST } from "@/auth";
// middleware.ts
export { auth as middleware } from "@/auth";

Sessions: cookie vs JWT

| Approach | Pro | Con | |----------|------|--------| | Session cookie (id → DB) | Immediate revocation, small cookie size | DB query on every check | | Stateless JWT | No DB check, horizontal scale | Complex revocation, large cookie size | | Session cookie + JWT refresh | Best of both | Complexity |

Recommended default: opaque session cookie stored in DB. Simpler, safer.

Mandatory cookie attributes

{
  httpOnly: true,       // JS cannot read the cookie (anti-XSS)
  secure: true,         // HTTPS only in prod
  sameSite: "lax",      // CSRF protection (strict if no OAuth)
  path: "/",
  maxAge: 60 * 60 * 24 * 7,  // 7 days
}

Password hashing

Never MD5, SHA-1, bcrypt < cost 12.

2026 recommendations:

  • argon2id (modern default) — OWASP recommends. argon2 package on npm.
  • bcrypt cost 12+ (acceptable, legacy)
  • scrypt (acceptable, native Node)
import argon2 from "argon2";

const hash = await argon2.hash(password, {
  type: argon2.argon2id,
  memoryCost: 19456,    // 19 MB
  timeCost: 2,
  parallelism: 1,
});

const valid = await argon2.verify(hash, password);

IMPORTANT: libs like better-auth / Lucia / NextAuth already hash correctly. Only reimplement if you're doing custom auth (and you shouldn't).

OAuth: correct config

Redirect URL

Always HTTPS in prod. Add http://localhost:3000/... for dev.

https://app.example.com/api/auth/callback/github

Minimum scopes

Request only what you need:

  • GitHub: read:user user:email (not repo if you don't read repos)
  • Google: openid email profile

Mandatory state parameter

Protects against OAuth CSRF. Modern libs do this automatically.

Authorization (after authentication)

Auth only verifies who the user is. For what they can do, you need roles/permissions.

Patterns

| Pattern | Usage | |---------|-------| | RBAC (Role-Based) | Fixed roles: admin, user, viewer | | ABAC (Attribute-Based) | Dynamic rules: "user can edit if owner" | | RLS (Row-Level Security) | Postgres/Supabase: SQL policies per user | | CASL / access-js | JS lib to express permissions |

Next.js middleware

// middleware.ts
import { NextResponse } from "next/server";
import { auth } from "@/lib/auth";

export async function middleware(request: NextRequest) {
  const session = await auth.api.getSession({ headers: request.headers });

  if (!session && request.nextUrl.pathname.startsWith("/dashboard")) {
    return NextResponse.redirect(new URL("/login", request.url));
  }

  if (session?.user.role !== "admin" && request.nextUrl.pathname.startsWith("/admin")) {
    return NextResponse.redirect(new URL("/403", request.url));
  }
}

2FA / MFA

TOTP (Google Authenticator) is the default.

// better-auth example
await authClient.twoFactor.enable({ password });
// Returns a QR code to scan
await authClient.twoFactor.verify({ code: "123456" });

Passkeys (WebAuthn) is the future. Native passwordless.

Security pitfalls

| Pitfall | Prevention | |-------|-----------| | Timing attack on password comparison | Use argon2.verify / constant-time compare | | User enumeration via login | Same error message for "unknown email" and "incorrect password" | | Session fixation | Regenerate session ID after login | | CSRF | SameSite cookie + OAuth state + Origin check on mutations | | XSS on token | httpOnly cookie (JS cannot read) | | Brute force | Rate limit per IP + per account, captcha after N failures | | Password reset leaks info | Same response "email sent" even if email doesn't exist | | OAuth open redirect | Validate the redirect_uri against a whitelist |

Auth audit checklist

  • [ ] Cookie: httpOnly, secure, sameSite correct
  • [ ] Password hashed with argon2id or bcrypt 12+
  • [ ] Rate limiting on /login, /register, /reset-password
  • [ ] Session regenerated after login and password change
  • [ ] Neutral error messages (no user enumeration)
  • [ ] Optional 2FA (mandatory for admins)
  • [ ] Logout client-side + server-side (invalidate DB session)
  • [ ] Password reset tokens: short duration (15-30 min), single use
  • [ ] Mandatory email verification before sensitive features
  • [ ] Audit log of auth actions (login, logout, password change)

Migration between solutions

| From → To | Strategy | |-----------|-----------| | NextAuth → better-auth | Dual-write sessions during the transition, batch user migration | | Supabase Auth → better-auth | Export users + password hashes if compatible, otherwise force reset | | Custom JWT → Lucia | Invalidate all JWTs, force re-login |

IMPORTANT: Never migrate without a prior DB backup and rollback plan.

Complement with the foundation

  • "Auth" section in docs/STACK-RECIPES.md
  • Rule .claude/rules/security.md: OWASP Top 10
  • Skill qa-security: full security audit
  • Skill dev-supabase: if Supabase stack

Expected output

  1. Chosen solution justified (no "rolling your own")
  2. Server and client config with secure cookies
  3. Authorization middleware if protected routes
  4. Optional 2FA for sensitive features
  5. Rate limiting on auth endpoints

Rules

IMPORTANT: NEVER roll your own auth (homemade JWT, custom password hashing).

IMPORTANT: Session cookie MUST BE httpOnly + secure + sameSite.

IMPORTANT: Password hashing = argon2id (default) or bcrypt cost 12+ (legacy).

YOU MUST rate-limit /login, /register, /reset-password (5-10 attempts/15min).

YOU MUST return the same error messages for "unknown user" and "incorrect password" (anti-enumeration).

NEVER expose reset/verification tokens in logs or shared URLs.

NEVER store passwords in clear text, even temporarily.

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.