Every time I started a new project, whether it was Formgrid, Sheetrocket, or a client build, the first week or two disappeared into authentication. Email verification tokens. Password reset flows. NextAuth configuration. A Prisma schema for users and sessions. Setting up the Google OAuth consent screen. Middleware for protected routes.
None of that is intellectually interesting. All of it is necessary. And it has to be done correctly, because a mistake in auth isn't a bug; it's a security vulnerability with someone's real account attached to it.
After doing this properly from scratch for the fifth time, I stopped. I built it once, the right way, open-sourced it, and made it the starting point for every project after this one.
The result is a production-ready authentication starter kit that gets a new Next.js project from zero to working auth in minutes instead of weeks.
What it includes
Email and password authentication with Zod validation. Not just a signup form, proper server-side validation that catches weak passwords, duplicate emails, and malformed input before any of it reaches the database.
Email verification. New users can't access protected routes until they verify their email, and the verification token expires after 24 hours. Without this, any email address, including ones the signer doesn't actually own, can be used to create an account.
Password reset with secure tokens. The reset token expires after one hour. Without an expiry, a leaked reset link is a permanent vulnerability sitting in someone's inbox forever. The token itself is hashed before it's stored, so even a full database breach doesn't hand over usable reset tokens.
Google OAuth with NextAuth.js v5. Handles the OAuth flow, stores the account link in the database, and merges correctly with an existing email account if the user originally signed up with a password. Getting that merge logic wrong is one of the most common auth bugs I've seen in real production apps.
Protected routes with Next.js middleware. Everything under the dashboard directory is protected automatically. The middleware checks the session and redirects unauthenticated users to login before the page component ever renders; no manual auth check copied into every page.
** Role-based access.** The User model has a role field, defaulting to USER, with support for ADMIN and any other role you want to add. Middleware can gate admin-only routes without touching every protected page individually.
A responsive dashboard layout in Tailwind. A clean starting point for the authenticated UI, so you can start building your actual feature immediately after cloning instead of also designing a dashboard shell first.
The stack, and the honest tradeoffs
Next.js 15 with the App Router. The current standard for React apps with server components and server actions. The App Router changes how auth is wired up compared to the Pages Router, and NextAuth v5 is built specifically for it.
Prisma with MySQL. Type safe queries with automatic migrations. MySQL for wide hosting compatibility, easily swapped for PostgreSQL by changing one line in the Prisma schema and the DATABASE_URL.
NextAuth.js v5. The current major version, with breaking changes from v4. The configuration pattern changed significantly, and most tutorials still floating around online use the old v4 pattern. This boilerplate uses the correct v5 approach.
Resend for transactional email. The most developer-friendly email API I've used. It's what Formgrid runs in production for verification and notification emails. The templates in the boilerplate are plain text and easy to reskin with your own branding.
Tailwind CSS. Utility-first styling that ships zero unused CSS to production.
Three decisions worth explaining, because most tutorials get them wrong
JWT sessions over database sessions
NextAuth supports two session strategies. Database sessions store a session record per login and validate it against the database on every request. JWT sessions encode the session data into a signed token and validate it cryptographically, no database query required.
Database sessions are more revocable; you can kill a session instantly by deleting its record. JWT sessions are faster, since there's no query on every authenticated request, but you can't invalidate one without extra infrastructure sitting on top. The boilerplate uses JWT for simplicity and speed. If your product needs immediate session revocation, for example, kicking someone out the moment their subscription lapses, that's the tradeoff worth knowing before you commit to this pattern.
Hashing verification and reset tokens
Verification tokens and password reset tokens are stored hashed in the database, never in plain text. That means even if someone reads the raw database, they can't use the stored tokens to verify accounts or reset passwords themselves. The plain text token only ever exists in the email link, and it's compared against the hash at submission time. Same principle as password hashing, applied to a temporary token instead of a permanent credential.
Auth checks belong in middleware, not in page components
Next.js middleware runs on the Edge runtime before the page ever renders. Putting the auth check there means a protected page is never rendered for an unauthenticated visitor, not even partially. Putting the check inside the page component instead means the page starts rendering and then redirects, which produces a flash of content the user was never supposed to see. Middleware is the correct place for the gate, not a convenience, but a correctness requirement.
How to use it
git clone git@github.com:allenarduino/nextjs-prisma-auth-boilerplate.git
cd nextjs-prisma-auth-boilerplate
npm install
Copy .env.example to .env and fill in:
DATABASE_URL, your MySQL connection stringNEXTAUTH_SECRET, a random 32-character string; generate one withopenssl rand -base64 32NEXTAUTH_URL, your app's base URLGOOGLE_CLIENT_IDandGOOGLE_CLIENT_SECRET, from the Google Cloud Console after creating an OAuth 2.0 credentialRESEND_API_KEY, from resend.com after creating an account and verifying a sending domainEMAIL_FROM, the sender address your verification and reset emails go out from, for exampleFormgrid <no-reply@yourdomain.com>
Then:
npx prisma generate
npx prisma db push
npm run dev
That's the whole setup. From clone to a working signup, verification, login, and password reset flow, in minutes.
What to build on top of it
A SaaS product. The auth layer is done. Add your subscription logic, your core features, and your billing integration. The User model's role field is already there to extend into a subscription tier if you need one.
A client project. Clone it, configure the environment variables for the client's domain and database, restyle the Tailwind to match their brand, and deploy. The auth is production-ready from day one, not a prototype you'll need to harden later.
A side project. Stop spending the first two weeks on auth and start building the part that's actually yours. The boilerplate handles the foundation so you can get to the feature that makes your project worth building in the first place.
How this connects to Formgrid
Formgrid runs a similar auth pattern, built in Express and Prisma instead of NextAuth, but the same principles apply underneath: email verification, hashed tokens, JWT sessions, Google OAuth, protected routes. Building this boilerplate was really just distilling those same patterns, ones already proven in a product real customers pay for, into a shareable starting point for the Next.js ecosystem specifically.
Where it stands right now
The repo has picked up 17 GitHub stars and 9 forks in a short amount of time, which is a decent early signal that the pain point is real and not just mine. You can browse the code at github.com/allenarduino/nextjs-prisma-auth-boilerplate or try the live demo at nextjs-prisma-auth-boilerplate.vercel.app.
Closing
Authentication is never the interesting part of a product. It's the necessary foundation everything else gets built on. Getting it right matters because getting it wrong means real security vulnerabilities attached to real users. Getting it done quickly matters because every week spent on auth is a week not spent on the feature that actually makes your product worth using.
Clone the repo, configure the environment, and go build the interesting part.
If you use it on a project, or find a way to improve it, I'd genuinely like to hear about it. The repo is open for contributions and issues at github.com/allenarduino/nextjs-prisma-auth-boilerplate. Reach me at allen@formgrid.dev.