Guide · Building real features
Authentication, safely
The one place where "don't build it yourself" is a rule, not advice.
Authentication looks simple: check a password, remember the user. It is not simple, and the failure mode is other people's accounts. This is the one area of your project where the correct move is to use something well-established and spend your creativity elsewhere.
Choose your level
Hosted auth — Clerk, Auth0, Supabase Auth, your framework's cloud offering. They handle passwords, resets, social login, and the mistakes. Costs money above a free tier. Fastest and safest.
A well-established library in your framework — Devise, Laravel's built-in auth, Django's, NextAuth. Free, battle-tested, more wiring.
Your own implementation — no.
There is one legitimate reason to hand-roll: you are doing it deliberately to learn, on a project with no real users. Fine. Don't put it in front of anybody.
What you must never do
Store passwords in any recoverable form. Hashing means bcrypt, scrypt or argon2, not SHA-256 and definitely not "encrypted". Email someone their existing password. Cap password length at something short. Roll your own token format. Compare secrets with == instead of a constant-time comparison.
The bit that actually goes wrong
Authentication is "who are you". Authorisation is "are you allowed to do this". Almost every real-world breach in a small app is the second one.
The classic: a page at /orders/1042 that checks you are logged in, and then shows you order 1042 — whoever it belongs to. Change the number, read someone else's data.
Here are my routes: <paste> For every route that reads or changes data, tell me: - Does it check that the logged-in user is allowed THIS record, not just that they are logged in? - What happens if I change the ID in the URL to someone else's? List every route where the answer is wrong, worst first, and show me the fix for the first one.
Run that audit on your own project today. It finds something in most vibe-coded apps, and it is the finding that matters most.
Sessions in short
Cookies for a normal website, marked HttpOnly, Secure and SameSite. Tokens if you have a separate frontend or mobile app. Sessions must expire, and logging out must actually invalidate on the server — not just delete the cookie.