Authentication patterns: sessions, JWTs and what to use when
The sessions-versus-JWT argument is really an argument about revocation. Decide how fast you need to be able to log someone out.
Current guidance is to require a minimum length of at least 8 and ideally 12 characters, allow long passphrases and all character types, check submissions against known breach lists, and stop forcing periodic rotation and composition rules. Hash with bcrypt, scrypt or Argon2, and offer MFA — preferring passkeys or an authenticator app over SMS.
| Rule | Current guidance |
|---|---|
| Minimum length | 8 required, 12+ recommended |
| Maximum length | At least 64 — never truncate |
| Composition rules | Do not impose them |
| Periodic expiry | No, unless compromise is suspected |
| Breach list check | Yes — reject known-compromised passwords |
| Password managers | Allow paste; never block it |
| Unicode and spaces | Accept all printable characters |
Composition rules produce Password1! rather than genuine entropy. Forced rotation produces Password1!, Password2!, Password3!. Both trade real security for the appearance of rigour, which is why modern standards recommend against them.
import { hash, verify } from "@node-rs/argon2";
// Store: Argon2id with current cost parameters, salt handled by the library
const stored = await hash(password, { memoryCost: 19456, timeCost: 2, parallelism: 1 });
// Verify — constant time, and rehash if parameters have moved on
const ok = await verify(stored, submitted);| Method | Security | Notes |
|---|---|---|
| Passkeys / WebAuthn | Strongest | Phishing-resistant; increasingly well supported |
| Hardware key (FIDO2) | Strongest | Excellent for administrative accounts |
| Authenticator app (TOTP) | Strong | Good default; phishable in real time |
| Push notification | Strong | Watch for approval fatigue attacks |
| Email code | Moderate | Only as strong as the email account |
| SMS | Weakest | SIM swap and interception risk — still better than nothing |
No. Current NIST guidance recommends against scheduled expiry because it drives predictable patterns. Force a change when there is evidence of compromise.
Yes, as an option. It is the weakest factor and vulnerable to SIM swapping, but it is dramatically better than no second factor and has the widest reach.
Use a k-anonymity API such as Have I Been Pwned's range endpoint, which lets you check a hash prefix without sending the password or its full hash.
Rarely. A maintained library or managed provider gives you hashing, MFA, breach checks, device management and audit logging that a custom implementation will not match.
ROVQIX Engineering
Engineering team, ROVQIX
The ROVQIX engineering team builds and maintains web platforms, APIs and infrastructure for clients across SaaS, ecommerce and enterprise. These notes come out of real production work — deploys, incidents, migrations and audits.
ROVQIXdesigns and builds production web platforms — Next.js front ends, Node.js APIs and the infrastructure behind them. Tell us what you're building and we'll scope it with you.
The sessions-versus-JWT argument is really an argument about revocation. Decide how fast you need to be able to log someone out.
Not a compliance document. This is the list we actually work through before a client site handles its first real user.
An API has no UI to hide behind. Every endpoint is directly reachable, and that is the correct way to think about securing one.
No spam. Just the occasional case study and craft breakdown.