<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Dan</title>
    <description>The latest articles on DEV Community by Dan (@halbonlabs).</description>
    <link>https://dev.to/halbonlabs</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3970566%2F466be80c-fe46-4f49-bfbe-7e4325459e78.jpg</url>
      <title>DEV Community: Dan</title>
      <link>https://dev.to/halbonlabs</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/halbonlabs"/>
    <language>en</language>
    <item>
      <title>Your CLAUDE.md should encode invariants, not a map of where files live</title>
      <dc:creator>Dan</dc:creator>
      <pubDate>Mon, 08 Jun 2026 12:39:33 +0000</pubDate>
      <link>https://dev.to/halbonlabs/your-claudemd-should-encode-invariants-not-a-map-of-where-files-live-m6n</link>
      <guid>https://dev.to/halbonlabs/your-claudemd-should-encode-invariants-not-a-map-of-where-files-live-m6n</guid>
      <description>&lt;p&gt;Most CLAUDE.md files I see are a folder map and a naming convention. That is close to the least valuable thing you can hand an agent, because it already infers structure from the repo. What it cannot infer are the rules that must never break, and the reasons behind them.&lt;/p&gt;

&lt;p&gt;An agent will happily write code that compiles, passes types, and quietly violates a security or data invariant. A file map does nothing to stop that. A list of invariants with reasons does.&lt;/p&gt;

&lt;p&gt;Here is the shape that has worked for me on Next.js + SQLite SaaS projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Encode invariants, with the reason
&lt;/h2&gt;

&lt;p&gt;Not "put queries in lib/db." Instead:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All writes go through a server action or route handler, and auth is checked there. The client is untrusted; the server is the only enforceable boundary.&lt;/li&gt;
&lt;li&gt;Every user-owned query includes an ownership predicate. SQLite has no row-level security, so this one line is the only thing stopping cross-tenant reads. Forgetting it is a silent data leak, not an error the agent will ever see.&lt;/li&gt;
&lt;li&gt;Never grant access or money state from a success URL, only from a verified server event.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The "and the reason" part matters. Claude follows a rule it understands far more reliably than one it takes on faith.&lt;/p&gt;

&lt;h2&gt;
  
  
  The SQLite gotcha worth stating outright (I normally run Postgres)
&lt;/h2&gt;

&lt;p&gt;I build on Postgres, where row-level security is a backstop: even if a query forgets its ownership filter, RLS can stop the cross-tenant read. SQLite has none. So on SQLite, "an ownership predicate on every user-scoped query" is not style advice, it is your entire multi-tenant boundary. If it is not stated as an invariant in the CLAUDE.md, an agent will eventually write a query without it and nothing will complain. (On Postgres, keep the predicate and keep RLS. Belt and suspenders.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Tell it how to work, not just what to build
&lt;/h2&gt;

&lt;p&gt;Invariants describe the destination. They do not stop the agent getting there in one giant, unreviewable leap. So the other half of a good CLAUDE.md is the working method.&lt;/p&gt;

&lt;p&gt;Mine is phase-gated micro-stepping, and the key move is that the agent does not authorise its own progress:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Work runs in phases (scope, build, verify, review, fix, ship) with a human checkpoint between each. The agent stops at every boundary, reports, and waits for an explicit go phrase. "looks good" does not advance it.&lt;/li&gt;
&lt;li&gt;The build phase is itself micro-stepped: one section at a time, with a typecheck, test, and pitfall scan after each, then a commit and a stop.&lt;/li&gt;
&lt;li&gt;A circuit breaker: if it cannot get a check green in about five tries, it stops and reports instead of looping forever.&lt;/li&gt;
&lt;li&gt;Defensive commits before multi-file changes, full implementations only (no // TODO stubs), and a tight state-summary handoff so a fresh session resumes without re-reading the repo.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A broken invariant shows up immediately in a small gated step; a big autonomous diff buries it. This is the part of a CLAUDE.md almost nobody writes, and it is the part that most changes how the agent behaves.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add a "danger paths to test" section
&lt;/h2&gt;

&lt;p&gt;The highest-leverage block. These are the flows that cost you money or data when they break, and the ones agents skip because they are boring:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;signup / login / logout&lt;/li&gt;
&lt;li&gt;protected route redirect when unauthenticated&lt;/li&gt;
&lt;li&gt;CRUD authorization (user A cannot touch user B's rows)&lt;/li&gt;
&lt;li&gt;migration on a fresh database&lt;/li&gt;
&lt;li&gt;migration on an existing database&lt;/li&gt;
&lt;li&gt;seed command run twice (no duplicates)&lt;/li&gt;
&lt;li&gt;production build&lt;/li&gt;
&lt;li&gt;first run after clone with only .env.example&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ending the file with "before you call this done, prove these still pass" turns the agent from a confident code generator into something closer to a careful engineer.&lt;/p&gt;

&lt;h2&gt;
  
  
  The full file
&lt;/h2&gt;

&lt;p&gt;Complete, opinionated CLAUDE.md for a Next.js + SQLite SaaS (Drizzle, server actions, the Next 16 caching rules, security baseline, the micro-stepping method, anti-patterns with reasons, and the danger-paths checklist). &lt;a href="https://gist.github.com/HalbonLabs/485186f4b2846bb1d13d2240651df21d" rel="noopener noreferrer"&gt;https://gist.github.com/HalbonLabs/485186f4b2846bb1d13d2240651df21d&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I build production Next.js templates for a living (Template Empire), so I think about this as "what stops a buyer's first clone from breaking," which turns out to be the same question as "what should the agent never get wrong." The deeper standards behind it are public: templateempire.io/standards&lt;/p&gt;

&lt;p&gt;What invariants are in your CLAUDE.md that you would not ship without?&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>ai</category>
      <category>webdev</category>
      <category>sqlite</category>
    </item>
    <item>
      <title>Most Next.js SaaS boilerplates ship you a landing page, not a product</title>
      <dc:creator>Dan</dc:creator>
      <pubDate>Mon, 08 Jun 2026 07:49:12 +0000</pubDate>
      <link>https://dev.to/halbonlabs/most-nextjs-saas-boilerplates-ship-you-a-landing-page-not-a-product-8na</link>
      <guid>https://dev.to/halbonlabs/most-nextjs-saas-boilerplates-ship-you-a-landing-page-not-a-product-8na</guid>
      <description>&lt;p&gt;I have bought a lot of Next.js SaaS boilerplates. Most have the same problem: the demo looks incredible, and the repo behind it is held together with tape.&lt;/p&gt;

&lt;p&gt;You see a stunning landing page, a pricing section, a dashboard screenshot. You pay. You clone it. An hour in you find auth with no session-refresh handling, a Stripe webhook that never verifies signatures, no tests, accessibility never considered, and "compliance" that means a Terms page someone pasted in.&lt;/p&gt;

&lt;p&gt;The landing page sells. The product underneath is the 80% nobody screenshots.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's actually missing
&lt;/h2&gt;

&lt;p&gt;The hard, not so glamorous parts are exactly the parts a screenshot can't show:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Auth that survives reality: session refresh, RBAC, httpOnly cookies, the logout-everywhere case.&lt;/li&gt;
&lt;li&gt;Billing that won't lose money: Stripe webhook signature verification, idempotency, the failed-payment and proration paths.&lt;/li&gt;
&lt;li&gt;Data safety: row-level isolation so tenant A never sees tenant B, parameterised queries, an audit trail.&lt;/li&gt;
&lt;li&gt;Compliance plumbing: a real data-export/DSAR flow, account deletion, cookie consent that honours Reject-All and GPC, not just legal pages.&lt;/li&gt;
&lt;li&gt;The boring guarantees: TypeScript strict with zero any, real test coverage, WCAG AA, a build that actually passes CI.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of that photographs well. All of it is what breaks at 2am once you have real users.&lt;/p&gt;

&lt;h2&gt;
  
  
  The thing you can't see is the thing you're buying
&lt;/h2&gt;

&lt;p&gt;When you buy a template, you are wiring your business onto a stranger's code with no evidence it is safe. You are trusting a screenshot. That is backwards.&lt;/p&gt;

&lt;p&gt;So when I built Template Empire, I made the verification the product, not the marketing. Every release runs through:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deterministic gates that don't care about opinions: typecheck, lint, full test suite, OWASP scan, a four-run Lighthouse matrix, Docker health check, dependency licence audit. Any gate fails, it does not ship.&lt;/li&gt;
&lt;li&gt;A multi-model review panel: 13 Claude specialists plus OpenAI Codex and Google Gemini, each reviewing from a different angle. Different models catch different blind spots. A finding raised by two or more auto-blocks at P0/P1.&lt;/li&gt;
&lt;li&gt;A buyer simulation: extract the ZIP, read the README, cp .env.example .env with zero manual edits, install, seed, log in, run. If the path a buyer takes breaks, it does not ship. That one dumb script has caught issues no code review did.&lt;/li&gt;
&lt;li&gt;A signed Quality Gate Report PDF in every download, so you can see exactly what was checked.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The receipts so far: 8,000+ automated tests, 1000+ issues found and fixed, 800+ pitfall patterns prevented, 0 P0/P1/P2 issues at release sign-off.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to audit before you buy ANY boilerplate
&lt;/h2&gt;

&lt;p&gt;You do not have to buy mine. But before you trust any paid starter with your business, check these:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Does the Stripe webhook handler verify the signature? Grep for it. If it's missing, walk away.&lt;/li&gt;
&lt;li&gt;Is there real multi-tenant isolation, or just a userId column and hope?&lt;/li&gt;
&lt;li&gt;Are there actual tests, or one token test file for the screenshot?&lt;/li&gt;
&lt;li&gt;Is auth using httpOnly cookies, or is a token sitting in localStorage?&lt;/li&gt;
&lt;li&gt;Is there a data-export and account-deletion path? You will need it for GDPR/CCPA.&lt;/li&gt;
&lt;li&gt;TypeScript strict with no any, or any everywhere once you open the files?&lt;/li&gt;
&lt;li&gt;Is there any evidence of QA at all, a report, a changelog, a versioned release history? Or just a v0.1.0 zip?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If a seller can't answer those, the landing page was the product.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I learned building the pipeline
&lt;/h2&gt;

&lt;p&gt;Two things. The AI reviewers are excellent at surfacing candidate issues and useless as a single source of truth: they only earn their keep paired with deterministic checks and a cross-confirmation rule. And the highest-value test in the whole system is the dumbest one, install it like a customer and see if it runs.&lt;/p&gt;

&lt;p&gt;The full process is public if you want to pick it apart: templateempire.io/standards. And if you want templates built this way: templateempire.io.&lt;/p&gt;

&lt;p&gt;What would you need to see in a quality report before you trusted a template enough to build a business on it? Curious to hear, that answer shapes what I build next.&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>webdev</category>
      <category>saas</category>
      <category>ai</category>
    </item>
    <item>
      <title>Auth in Next.js SaaS starters: redirect loops, OAuth callbacks, magic links, and session drift</title>
      <dc:creator>Dan</dc:creator>
      <pubDate>Sat, 06 Jun 2026 20:38:26 +0000</pubDate>
      <link>https://dev.to/halbonlabs/auth-in-nextjs-saas-starters-redirect-loops-oauth-callbacks-magic-links-and-session-drift-2383</link>
      <guid>https://dev.to/halbonlabs/auth-in-nextjs-saas-starters-redirect-loops-oauth-callbacks-magic-links-and-session-drift-2383</guid>
      <description>&lt;p&gt;&lt;strong&gt;A practical guide to auditing authentication in a Next.js SaaS starter before it breaks across preview URLs, production domains, and protected routes.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Authentication is one of the easiest features to demo and one of the easiest features to break.&lt;/p&gt;

&lt;p&gt;A sign-in button proves almost nothing by itself. Real SaaS auth has to survive production domains, preview deployments, OAuth callbacks, magic links, session refresh, protected routes, billing states, role checks, account deletion, and sometimes organisations or custom domains.&lt;/p&gt;

&lt;p&gt;When evaluating a Next.js SaaS starter, treat auth as a system, not a screen.&lt;/p&gt;

&lt;h2&gt;
  
  
  The happy-path demo hides the hard parts
&lt;/h2&gt;

&lt;p&gt;The usual demo flow is simple:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click sign in.&lt;/li&gt;
&lt;li&gt;Use a test account.&lt;/li&gt;
&lt;li&gt;Land on the dashboard.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That does not prove much.&lt;/p&gt;

&lt;p&gt;Real users create edge cases immediately:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;they click a magic link on another device;&lt;/li&gt;
&lt;li&gt;they use Google OAuth on a preview deployment;&lt;/li&gt;
&lt;li&gt;their session expires while a form is open;&lt;/li&gt;
&lt;li&gt;they try to access &lt;code&gt;/dashboard&lt;/code&gt; while logged out;&lt;/li&gt;
&lt;li&gt;they cancel checkout and return later;&lt;/li&gt;
&lt;li&gt;they use a workspace invite link;&lt;/li&gt;
&lt;li&gt;they sign in with a different provider using the same email;&lt;/li&gt;
&lt;li&gt;they delete their account;&lt;/li&gt;
&lt;li&gt;they are removed from a team.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A production-ready starter should explain these paths or at least provide clean extension points.&lt;/p&gt;

&lt;h2&gt;
  
  
  Redirect loops usually mean route boundaries are unclear
&lt;/h2&gt;

&lt;p&gt;Redirect loops happen when the application cannot clearly decide whether a route is public, auth-only, protected, or already authenticated.&lt;/p&gt;

&lt;p&gt;Common causes include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;middleware running on routes it should ignore;&lt;/li&gt;
&lt;li&gt;auth pages redirecting to dashboard while dashboard redirects back to auth;&lt;/li&gt;
&lt;li&gt;callback routes being protected by mistake;&lt;/li&gt;
&lt;li&gt;missing environment variables for the canonical app URL;&lt;/li&gt;
&lt;li&gt;inconsistent trailing slash or base-path behaviour;&lt;/li&gt;
&lt;li&gt;session checks that disagree between middleware and server components.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The fix is usually architectural rather than cosmetic. A good starter should have an explicit route map:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;public marketing routes;&lt;/li&gt;
&lt;li&gt;auth routes;&lt;/li&gt;
&lt;li&gt;callback routes;&lt;/li&gt;
&lt;li&gt;protected app routes;&lt;/li&gt;
&lt;li&gt;admin routes;&lt;/li&gt;
&lt;li&gt;API routes;&lt;/li&gt;
&lt;li&gt;webhook routes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If everything is protected by one broad matcher and exceptions are scattered around the codebase, expect pain.&lt;/p&gt;

&lt;h2&gt;
  
  
  OAuth callbacks need environment discipline
&lt;/h2&gt;

&lt;p&gt;OAuth providers are strict about callback URLs. That is good security, but it creates setup friction.&lt;/p&gt;

&lt;p&gt;A starter should document the callback URLs needed for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;local development;&lt;/li&gt;
&lt;li&gt;preview deployments;&lt;/li&gt;
&lt;li&gt;production;&lt;/li&gt;
&lt;li&gt;custom domains;&lt;/li&gt;
&lt;li&gt;subdomains if relevant.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It should also explain which environment variable represents the public application URL and how that value changes by environment.&lt;/p&gt;

&lt;p&gt;Red flags:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;callback URLs only shown for &lt;code&gt;localhost&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;no mention of preview URLs;&lt;/li&gt;
&lt;li&gt;auth provider setup hidden behind “configure your provider”;&lt;/li&gt;
&lt;li&gt;hard-coded base URLs;&lt;/li&gt;
&lt;li&gt;no troubleshooting section for OAuth redirects.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your buyer cannot configure OAuth without guessing, the starter is not handoff-ready.&lt;/p&gt;

&lt;h2&gt;
  
  
  Magic links need a clear product flow
&lt;/h2&gt;

&lt;p&gt;Magic links are convenient, but they create state questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How long does the link last?&lt;/li&gt;
&lt;li&gt;What happens if it is opened on another device?&lt;/li&gt;
&lt;li&gt;Where does the user land after verification?&lt;/li&gt;
&lt;li&gt;Does the app preserve the intended destination?&lt;/li&gt;
&lt;li&gt;What happens if the user purchased before creating an account?&lt;/li&gt;
&lt;li&gt;Are used or expired links handled clearly?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A starter that supports magic links should include the UX around them: email copy, expired-link screen, resend path, and redirect destination handling.&lt;/p&gt;

&lt;p&gt;Auth is not only cryptography. It is also user experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Session drift creates confusing bugs
&lt;/h2&gt;

&lt;p&gt;Session drift happens when different parts of the app disagree about who the user is or what they can access.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;middleware sees a stale token;&lt;/li&gt;
&lt;li&gt;a server component fetches a fresh user;&lt;/li&gt;
&lt;li&gt;a client component still has old state;&lt;/li&gt;
&lt;li&gt;billing status changed by webhook but the dashboard still shows old access;&lt;/li&gt;
&lt;li&gt;a role changed but cached data still shows admin controls.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A robust SaaS starter defines where the source of truth lives.&lt;/p&gt;

&lt;p&gt;For sensitive checks, prefer server-side decisions. Client state can improve interactivity, but it should not be the final authority for access.&lt;/p&gt;

&lt;h2&gt;
  
  
  Auth and billing should be connected carefully
&lt;/h2&gt;

&lt;p&gt;Many SaaS starters treat auth and billing as separate modules. In the product, they interact constantly.&lt;/p&gt;

&lt;p&gt;Questions to ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Can someone buy before creating an account?&lt;/li&gt;
&lt;li&gt;If so, how is payment linked to the eventual user?&lt;/li&gt;
&lt;li&gt;Can users sign up with OAuth after paying with an email link?&lt;/li&gt;
&lt;li&gt;What happens if the billing email differs from the login email?&lt;/li&gt;
&lt;li&gt;Can an unpaid user access account settings?&lt;/li&gt;
&lt;li&gt;Can a cancelled user still log in but not use paid features?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A good starter does not need to force one answer. It should make the chosen answer explicit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Roles should not be only visual
&lt;/h2&gt;

&lt;p&gt;Hiding a button is not access control. If the server still accepts the action, the permission model is broken.&lt;/p&gt;

&lt;p&gt;A SaaS starter should enforce permissions at the boundary where data changes or sensitive data is read.&lt;/p&gt;

&lt;p&gt;Look for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;typed roles;&lt;/li&gt;
&lt;li&gt;central permission helpers;&lt;/li&gt;
&lt;li&gt;server-side checks;&lt;/li&gt;
&lt;li&gt;protected admin routes;&lt;/li&gt;
&lt;li&gt;audit logs for sensitive actions;&lt;/li&gt;
&lt;li&gt;clear separation between billing entitlements and user roles.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Billing answers “has this account paid?” Roles answer “what can this user do?” They are related, but they are not the same.&lt;/p&gt;

&lt;h2&gt;
  
  
  Account lifecycle matters
&lt;/h2&gt;

&lt;p&gt;Auth does not end at sign-in.&lt;/p&gt;

&lt;p&gt;A production-ready starter should consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;profile editing;&lt;/li&gt;
&lt;li&gt;email changes;&lt;/li&gt;
&lt;li&gt;password reset or provider-managed equivalent;&lt;/li&gt;
&lt;li&gt;account deletion;&lt;/li&gt;
&lt;li&gt;session invalidation;&lt;/li&gt;
&lt;li&gt;data export;&lt;/li&gt;
&lt;li&gt;team removal;&lt;/li&gt;
&lt;li&gt;admin suspension;&lt;/li&gt;
&lt;li&gt;audit logging.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even if the template ships a lean version, the data model should not make these impossible later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Auth audit checklist
&lt;/h2&gt;

&lt;p&gt;Before trusting a Next.js SaaS starter’s auth layer, check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Public, auth, callback, protected, admin, and webhook routes are separated.&lt;/li&gt;
&lt;li&gt;[ ] Middleware or proxy matchers are documented.&lt;/li&gt;
&lt;li&gt;[ ] The authoritative access check runs in a server component, route handler, or the data layer, not in middleware alone.&lt;/li&gt;
&lt;li&gt;[ ] OAuth callback URLs are shown for local and production.&lt;/li&gt;
&lt;li&gt;[ ] Preview URL behaviour is explained.&lt;/li&gt;
&lt;li&gt;[ ] Magic link expiry and redirect behaviour is clear.&lt;/li&gt;
&lt;li&gt;[ ] Sessions are checked server-side for sensitive routes.&lt;/li&gt;
&lt;li&gt;[ ] Roles and permissions are typed or centralised.&lt;/li&gt;
&lt;li&gt;[ ] Billing entitlements are not confused with user roles.&lt;/li&gt;
&lt;li&gt;[ ] Account deletion and export are considered.&lt;/li&gt;
&lt;li&gt;[ ] Auth errors have user-facing states.&lt;/li&gt;
&lt;li&gt;[ ] The docs include common redirect and callback troubleshooting.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Template Empire angle
&lt;/h2&gt;

&lt;p&gt;Template Empire treats auth as part of the foundation: route protection, user management, compliance scaffolding, billing interaction, and auditability all matter. The goal is not simply to make sign-in work in a demo. The goal is to make auth understandable enough that a buyer can safely build on it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://nextjs.org/docs/app/guides/authentication" rel="noopener noreferrer"&gt;Next.js authentication guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nextjs.org/docs/app/api-reference/file-conventions/middleware" rel="noopener noreferrer"&gt;Next.js middleware file convention&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://owasp.org/Top10/2021/A07_2021-Identification_and_Authentication_Failures/" rel="noopener noreferrer"&gt;OWASP: Identification and Authentication Failures&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://templateempire.io/standards" rel="noopener noreferrer"&gt;Template Empire standards&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>oauth</category>
      <category>nextjs</category>
      <category>webdev</category>
      <category>authentication</category>
    </item>
  </channel>
</rss>
