Skip to content
Back to skills

Auth Doctor

ASecurity

Diagnose and fix issues in existing auth setups. Scans environment, files, security, middleware, OAuth, database, and dangerous code patterns. Produces scored health report with actionable fixes.

  • 10 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added August 31, 2026
developmentgobashsqlreactnextjsnodetestinggitapidatabase

Works with

  • cli
  • api

Security analysis

A100/100

Scanned August 31, 2026

npx -y skills add ShipWithAI/shipwithai-plugins --skill auth-doctor --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Auth Doctor?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Auth Doctor
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/shipwithai-auth-doctor/badge)](https://www.skillsdirectory.com/skills/shipwithai-auth-doctor)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: auth-doctor
description: "Diagnose and fix issues in existing auth setups. Scans environment, files, security, middleware, OAuth, database, and dangerous code patterns. Produces scored health report with actionable fixes."
version: 1.0.0
license: MIT
---

# Auth Doctor — Diagnostic Guide

Health check for existing authentication setups. Detects misconfigurations, missing files, security issues, and dangerous code patterns across Better Auth and Firebase Auth projects.

## When to Use

- After running `/shipwithai-auth:setup` — final validation
- Auth is broken and you don't know why
- Before deploying to production — pre-flight check
- After upgrading auth packages or Next.js version
- Periodic maintenance check

## Step 1: Auto-Discover Project Stack

Run the **same discovery logic** as `skills/auth-setup/SKILL.md` → Step 0. This ensures setup and doctor use identical detection.

Scan for:

**1a. Framework & Versions** (same as setup Step 0a/0b):
- `next.config.*` → Next.js (extract version from `package.json`)
- App Router vs Pages Router
- React version, Node.js version

**1b. Auth Provider** (same as setup Step 0d):
- `better-auth` in deps → Better Auth
- `firebase` in deps → Firebase
- `@clerk/nextjs`, `next-auth`, `@supabase/ssr` → respective provider
- If no auth detected → ❌ STOP: "No auth setup detected. Run `/shipwithai-auth:setup` first."

**1c. ORM & Database** (same as setup Step 0c):
- `drizzle.config.ts` → Drizzle | `prisma/schema.prisma` → Prisma
- Check database type from drizzle config or deps (SQLite, PostgreSQL, MySQL)

**1d. Package Manager** (same as setup Step 0f):
- Lockfile detection

**1e. UI Library** (same as setup Step 0g):
- `components.json` → shadcn/ui | Tailwind | MUI/Chakra/Mantine

**1e. Existing Auth Pages & Routes** (same as setup Step 0e):
- Check for auth pages: `src/app/(auth)/login/`, `src/app/(auth)/register/`, etc.
- Check for API routes: `src/app/api/auth/`
- Check for middleware: `src/middleware.ts`, `middleware.ts`

**1f. Auth-specific detection:**
- `.env.local` or `.env` → configured env vars
- OAuth providers: check env vars for `GOOGLE_CLIENT_ID`, `GITHUB_CLIENT_ID`, `APPLE_CLIENT_ID`
- Email: check for `resend` in deps or `RESEND_API_KEY` in env

**Output the detection summary before proceeding:**
```
🔍 Auth Doctor — Scanning project...

Framework:   Next.js 14.2.18 (App Router)
Provider:    Better Auth (better-auth@1.2.3)
ORM:         Drizzle (drizzle-orm@0.30.10)
Database:    SQLite (better-sqlite3)
Package mgr: npm
UI:          shadcn/ui (new-york)
OAuth:       Google ✓, GitHub ✗
Email:       Resend ✓
```

## Step 2: Run Diagnostic Checks

Run each category. If `$ARGUMENTS` specifies a category, run ONLY that one. Otherwise run all 8.

### Category 1: Environment Variables (`env`)

**Check .env.local exists:**
- ❌ CRITICAL if missing entirely
- Read `.env.local` (or `.env` as fallback)

**Check provider-specific required vars:**

| Provider | Required |
|----------|----------|
| Better Auth | `BETTER_AUTH_SECRET`, `BETTER_AUTH_URL` |
| Firebase | `NEXT_PUBLIC_FIREBASE_API_KEY`, `NEXT_PUBLIC_FIREBASE_PROJECT_ID`, `NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN`, `FIREBASE_PROJECT_ID`, `FIREBASE_CLIENT_EMAIL`, `FIREBASE_PRIVATE_KEY` |

**Check var quality (not just existence):**
- `BETTER_AUTH_SECRET` — must be ≥32 chars (recommend 64 hex chars from `openssl rand -hex 32`)
- `BETTER_AUTH_URL` — must start with `http://` or `https://`
- `NEXT_PUBLIC_FIREBASE_API_KEY` — must start with `AIza`
- `FIREBASE_PRIVATE_KEY` — must contain `-----BEGIN`

**Check for test keys in production:**
- ⚠️ WARNING if `BETTER_AUTH_URL=http://localhost` in a project with `NODE_ENV=production` indicators
- ⚠️ WARNING if `RESEND_API_KEY=re_test_` (test key can't send to real emails)

**Check OAuth var pairs:**
- If `GOOGLE_CLIENT_ID` exists → `GOOGLE_CLIENT_SECRET` must also exist (and vice versa)
- If `GITHUB_CLIENT_ID` exists → `GITHUB_CLIENT_SECRET` must also exist
- If `APPLE_CLIENT_ID` exists → `APPLE_CLIENT_SECRET` must also exist
- ❌ CRITICAL if one exists without the other

**Check email vars (if Resend detected):**
- `RESEND_API_KEY` — must start with `re_`
- `EMAIL_FROM` — must be a valid email format
- ⚠️ WARNING if `EMAIL_FROM=onboarding@resend.dev` — can only send to account owner email

### Category 2: File Structure (`files`)

**Check all required files per provider:**

**Better Auth required files:**
```
src/db/schema.ts                              — Drizzle schema with auth tables
src/lib/db.ts                                 — Drizzle client
src/lib/auth.ts                               — Better Auth server config
src/lib/auth-client.ts                        — Better Auth client
src/app/api/auth/[...all]/route.ts            — API route handler
src/middleware.ts                              — Route protection middleware
src/app/(auth)/login/page.tsx                 — Login page
src/app/(auth)/register/page.tsx              — Register page
src/app/(auth)/forgot-password/page.tsx       — Forgot password page
src/app/(auth)/reset-password/page.tsx        — Reset password page
src/app/(protected)/layout.tsx                — Protected layout with session check
src/app/(protected)/dashboard/page.tsx        — Dashboard page
src/app/(protected)/dashboard/dashboard-client.tsx — Dashboard client component
src/components/icons.tsx                      — OAuth provider icons
.env.example                                  — Env var template
drizzle.config.ts                             — Drizzle Kit config
```

**Firebase required files:**
```
src/lib/firebase.ts                           — Client SDK init
src/lib/firebase-admin.ts                     — Admin SDK init
src/lib/firebase-session.ts                   — Session cookie helpers
src/lib/auth-server.ts                        — getServerUser() helper
src/app/api/auth/session/route.ts             — Session API with CSRF
src/middleware.ts                              — Route protection middleware
src/app/(auth)/login/page.tsx                 — Login page
src/app/(auth)/register/page.tsx              — Register page
src/app/(auth)/forgot-password/page.tsx       — Forgot password page
src/app/(auth)/reset-password/page.tsx        — Reset password page
src/app/(protected)/layout.tsx                — Protected layout with session verification
src/app/(protected)/dashboard/page.tsx        — Dashboard page
src/app/(protected)/dashboard/dashboard-client.tsx — Dashboard client component
src/components/icons.tsx                      — OAuth provider icons
.env.example                                  — Env var template
```

**For each missing file:** Report ❌ with the source asset path to copy from.

**Cross-reference imports:** For each existing file, check that its imports resolve:
- Read the file, extract `import ... from "..."` statements
- Check that aliased imports (`@/lib/auth`, `@/components/icons`, etc.) have corresponding files
- ❌ CRITICAL if an import target doesn't exist (build will fail)

### Category 3: Dependencies (`deps`)

**Check provider packages installed:**
- Read `package.json` dependencies + devDependencies
- Verify provider package exists and check version compatibility

**Check for known breaking versions:**
- `better-auth` < 0.4.0 — major API changes
- `drizzle-kit` with `driver` field instead of `dialect` — deprecated in 0.21+
- `shadcn` > 2.1.0 with Tailwind v3 — incompatible (pitfall #44)
- `next` >= 16 with `middleware.ts` — deprecated in favor of `proxy.ts` (pitfall #37)

**Check peer dependency conflicts:**
```bash
npm ls 2>&1 | grep "peer dep" | head -20
```

**Check node_modules exists:**
- ❌ CRITICAL if missing

### Category 4: Security (`security`)

**Check .gitignore:**
- `.env` and `.env.local` must be listed
- `sqlite.db` should be listed (if SQLite)
- ❌ CRITICAL if `.env` not in `.gitignore`

**Scan for hardcoded secrets in source files:**
- Scan `src/` for patterns: `sk_live_`, `sk_test_`, `re_`, `AIza`, `-----BEGIN`, `whsec_`
- Exclude `.env*` files and `node_modules/`
- ❌ CRITICAL if found in `.ts`/`.tsx` source files

**Check next.config for security headers:**
- ⚠️ WARNING if no security headers configured (X-Frame-Options, HSTS, CSP)
- Reference: `assets/config/next.config.ts`

**Check for better-sqlite3 in serverComponentsExternalPackages (Better Auth + SQLite):**
- Next.js 14: must be in `experimental.serverComponentsExternalPackages`
- Next.js 15+: must be in `serverExternalPackages`
- ❌ CRITICAL if missing — causes "Cannot find module" at runtime

### Category 5: Dangerous Code Patterns (`patterns`)

These checks map directly to SKILL.md Critical Code Rules R1–R8.

**R1 — Module-scope SDK instantiation:**
- Scan `src/lib/email.ts` for `new Resend(` at module scope (outside functions)
- Scan `src/lib/auth.ts` for `new Stripe(` or `new Resend(` at module scope
- ❌ CRITICAL — crashes during build/SSR because env vars unavailable at module evaluation

**R4 — Better Auth middleware using auth() wrapper:**
- Scan `src/middleware.ts` for `export { auth as middleware }` or `export default auth(`
- ❌ CRITICAL — `auth()` is Auth.js (NextAuth v5), not Better Auth

**R5 — Firebase middleware decoding JWT:**
- Scan `src/middleware.ts` for `atob(`, `Buffer.from(.*base64`, `firebase-admin`, `verifyIdToken`, `verifySessionCookie`
- ❌ CRITICAL — Edge Runtime cannot run Firebase Admin SDK

**R2 — Redirect before session cookie (Firebase):**
- Scan login/register pages for `router.push` without preceding `await createSessionCookie`
- ⚠️ WARNING — session may not persist

**R3 — Sign-out order (Firebase):**
- Scan dashboard-client for sign-out logic
- Server cookie delete should happen BEFORE client `signOut()`
- ⚠️ WARNING if order is reversed

**R7 — Missing Suspense wrapper:**
- Scan `reset-password/page.tsx` for `useSearchParams()` without `<Suspense>`
- ❌ CRITICAL — `next build` fails in Next.js 14+

**R8 — Missing files from checklist:**
- Already covered in Category 2, but double-check `auth-client.ts` specifically
- ❌ CRITICAL — cascading import errors

### Category 6: Middleware (`middleware`)

**Check middleware exists:**
- Look for `src/middleware.ts` or `middleware.ts`
- ⚠️ WARNING if missing

**Check middleware pattern matches provider:**

| Provider | Correct pattern | Wrong pattern |
|----------|----------------|---------------|
| Better Auth | `request.cookies.get("better-auth.session_token")` | `auth()`, `getSession()`, `headers()` |
| Firebase | `request.cookies.get("__session")` | `verifyIdToken`, `firebase-admin`, `atob` |

**Check route matcher:**
- ⚠️ WARNING if no `export const config = { matcher: [...] }` — middleware runs on all routes including static assets
- Verify matcher includes protected routes (`/dashboard`, `/profile`, etc.)
- Verify matcher excludes auth routes (`/login`, `/register`, `/api/auth`)

**Check for headers() import (Better Auth):**
- `headers()` from `next/headers` is NOT available in Edge Runtime middleware
- ❌ CRITICAL if imported

### Category 7: OAuth Configuration (`oauth`)

**For each detected OAuth provider (Google, GitHub, Apple):**

**Check env vars complete:**
- Client ID + Client Secret must both be set
- ❌ CRITICAL if one missing

**Check auth config includes the provider:**
- Better Auth: `socialProviders` in `src/lib/auth.ts` should list the provider
- Firebase: Provider must be enabled in Firebase Console (can't auto-check, but warn user)

**Check callback URL format:**
- Better Auth: `{BETTER_AUTH_URL}/api/auth/callback/{provider}`
- Firebase: `https://{PROJECT}.firebaseapp.com/__/auth/handler`
- ⚠️ WARNING: remind user to verify callback URL is registered in provider console

**Check for common Google OAuth mistakes (Firebase):**
- ⚠️ WARNING: remind about 5-step OAuth setup checklist in `references/05-firebase-auth-guide.md`
- Testing mode: test user emails must be added in Google Cloud Console

### Category 8: Database (`database`)

**Better Auth + Drizzle:**

**Check drizzle.config.ts:**
- Must exist at project root
- Must use `dialect: "sqlite"` (NOT `driver: "better-sqlite"`)
- ❌ CRITICAL if uses deprecated `driver` field

**Check schema has auth tables:**
- Read `src/db/schema.ts`
- Must contain: `user`, `session`, `account`, `verification` tables
- ❌ CRITICAL if any missing

**Check db.ts passes schema:**
- `drizzle(client, { schema })` — schema must be imported and passed
- ❌ CRITICAL if schema not passed — queries will fail

**Check auth.ts passes schema to adapter:**
- `drizzleAdapter(db, { provider: "sqlite", schema })` — schema must be passed
- ❌ CRITICAL if schema missing in adapter config

**Check database file exists (SQLite):**
- ⚠️ WARNING if `sqlite.db` doesn't exist — needs `npx drizzle-kit push` to create tables

**Check migration status:**
- If `drizzle/` directory has migration files, check they've been applied
- ⚠️ WARNING if migrations exist but database doesn't have the tables

## Step 3: Produce Health Report

After all checks complete, produce a scored report:

```
╔══════════════════════════════════════════════════╗
║          🔐 Auth Doctor — Health Report          ║
╠══════════════════════════════════════════════════╣
║ Provider:  Better Auth                           ║
║ Score:     18/22 checks passed                   ║
╚══════════════════════════════════════════════════╝

Category                 Status    Issues
─────────────────────────────────────────
1. Environment Variables   ✅       0
2. File Structure          ❌       2 missing files
3. Dependencies            ✅       0
4. Security                ⚠️       1 warning
5. Code Patterns           ✅       0
6. Middleware              ✅       0
7. OAuth Configuration     ❌       1 critical
8. Database                ⚠️       1 warning

──── CRITICAL (fix immediately) ─────────

❌ src/components/icons.tsx missing
   → Copy from plugin: assets/components/shared/icons.tsx

❌ GITHUB_CLIENT_ID set but GITHUB_CLIENT_SECRET missing
   → Add GITHUB_CLIENT_SECRET to .env.local

──── WARNINGS (review recommended) ──────

⚠️  No security headers in next.config
   → Merge from plugin: assets/config/next.config.ts

⚠️  sqlite.db not found — run: npx drizzle-kit push
```

**Ordering rules:**
1. ❌ CRITICAL items first (will break at runtime)
2. ⚠️ WARNING items second (works but risky)
3. ✅ PASS items last (or omit for brevity)

## Step 4: Offer to Fix

After presenting the report:

```
Found {N} issues ({X} critical, {Y} warnings).

Would you like me to fix them?
A) Fix all — apply all safe fixes automatically
B) Fix critical only — fix only ❌ items
C) Show me the fixes first — explain what I'd change, then confirm
D) Skip — I'll fix them manually
```

**CRITICAL rules for fixing:**
- NEVER modify `.env.local` values without user confirmation (may contain real secrets)
- NEVER delete files — only create missing ones or patch existing
- For env var issues: show what needs to change, let user update
- For missing files: copy from plugin assets (show source path)
- For code pattern issues: show the diff before applying
- For drizzle.config.ts `driver` → `dialect`: safe to auto-fix

## Step 5: Post-Fix Verification

After fixes are applied, re-run ONLY the failed categories to confirm they now pass.

If all checks pass:
```
✅ All issues resolved! Auth setup is healthy.

Next steps:
- Run `npm run build` to verify the full build
- Test the auth flow: register → verify email → login → dashboard → sign out
- Review references/09-common-pitfalls.md for 60 production pitfalls
```

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.