Auth that is actually safe
Passwords, sessions, CSRF, and the blast radius of each decision.
Authentication is where a tiny mistake becomes a headline. Build the boring, audited version.
Passwords
- Never store a recoverable password. Argon2id with a random salt and a per-hash cost is the current default.
- Enforce a minimum length (10+). Length beats complexity.
- Compare hashes in constant time so timing leaks nothing.
Sessions
Issue an opaque, random token, store only its hash, and set it as an HttpOnly cookie:
Set-Cookie: bl_session=…; HttpOnly; Path=/; SameSite=LaxHttpOnly keeps JavaScript out of it. Sending the token in a cookie keeps it out of your logs and URLs.
CSRF
A session cookie authenticates the browser — which means a malicious site could make the browser act. The fix: for mutating requests, require a token that the attacker's page cannot read, plus confirm the Origin matches.
X-CSRF-Token: <readable, per-session value>
Origin: http://localhost:3001Roles
Model roles as an ordered ladder and check the lowest rank that can act, not a string equality:
LEARNER < INSTRUCTOR < ADMIN < SUPER_ADMINA user directory (PATCH /users/{id}) that lets you change role and status must also revoke sessions when an account is suspended and refuse to modify super admins — the two classic escape hatches.
The audit reflex
Every state change should leave a trace: who, what, when, from where. The audit log is not a feature; it is the answer to "what happened?" after the incident.