How does the register and login flow work?
Bash
Why hash passwords with bcrypt?
How do I write the register and login handlers?
Js
What should go inside the token?
Bash
How do I verify the token in middleware?
Js
Js
Where should I store the JWT: cookie or localStorage?
- localStorage can be read by any JavaScript running on your page. One XSS bug, or one compromised npm package in your frontend, and the token can be copied out.
- An httpOnly cookie cannot be read by scripts, so it cannot be copied that way. Browsers attach it automatically, though, which opens the door to CSRF, where another site triggers a request in the user's name.
What about refresh tokens?
A checklist of common mistakes
- Passwords are hashed with bcrypt at cost 10 or higher, never with a fast hash, and over-long input is rejected.
- JWT_SECRET is long, random and loaded from the environment, not a word like "secret" in the source.
- Tokens always carry expiresIn, and jwt.verify pins the algorithm.
- The payload holds an id and nothing private.
- The token cookie is httpOnly, secure in production and has a sameSite setting.
- Login has a rate limit and one generic error message for unknown emails and wrong passwords, with similar response times.
- Protected routes use the verification middleware, and role or ownership checks happen on the server.