What Happens When You Type a URL and Press Enter
DNS lookups, TCP and TLS handshakes, HTTP requests, servers, and the browser's rendering pipeline. The whole journey of a web page, explained so it finally clicks.
Read →Password reset is one of the most attacked features in any app. How to generate and store reset tokens, avoid leaking which emails exist, expire and invalidate correctly, and protect users after a reset.
"Forgot your password?" is a tiny link with a huge responsibility. A weak reset flow lets attackers take over accounts without ever knowing the password, which makes it one of the most targeted features in any web app. The good news: a secure flow follows a clear recipe.
Simple. The security lives in the details of each step.
Always show the same message, whether or not the email is registered:
"If an account exists for that email, we've sent a password reset link."
Otherwise attackers can use your form to discover which emails have accounts (account enumeration), then target them. Also try to keep response times similar in both cases, for example by sending the email from a background job either way. (Background jobs.)
Use a cryptographically secure random generator, never Math.random(), timestamps or user IDs:
import crypto from 'node:crypto'
const token = crypto.randomBytes(32).toString('base64url') // send this in the email
const tokenHash = crypto.createHash('sha256').update(token).digest('hex') // store this
Treat reset tokens like passwords. If your database leaks, plain tokens would let attackers reset anyone's password. Store a hash (a fast hash like SHA-256 is fine here, since the token is long and random), along with:
When a user requests a new reset, invalidate any previous unused tokens for that account.
https://yourapp.com/reset-password?token=Gx9k...
Referrer-Policy: no-referrer (or similar) so the token isn't leaked to third-party scripts or links via the Referer header.When the user submits a new password:
Without limits, attackers can flood users with reset emails, use your app to spam, or brute-force tokens.
Reset emails are only as safe as the email channel. Make sure they arrive reliably (and not in spam) with proper SPF, DKIM and DMARC. (Email deliverability.) Keep the email short, clear about what was requested, and explicit that the user can ignore it if they didn't ask for a reset.
Usually 15 to 60 minutes. Short lifetimes limit the window for misuse if the email is intercepted or the inbox is compromised.
Store only a hash of the token, along with its expiry and usage status, never the raw token. Treat it with the same care as a password.
No. Show the same message for every request so attackers can't discover which email addresses have accounts.
DNS lookups, TCP and TLS handshakes, HTTP requests, servers, and the browser's rendering pipeline. The whole journey of a web page, explained so it finally clicks.
Read →There are dozens of HTTP status codes, but about fifteen cover nearly everything. What each one means, when to return it, and the mix-ups (401 vs 403, 301 vs 302) that confuse everyone.
Read →A, AAAA, CNAME, MX, TXT and NS records in plain English, why DNS changes seem slow, and the troubleshooting commands that tell you what is really going on.
Read →