Advanced·20 min·web · auth · security · jwt · bcrypt
Auth: password hashing + JWTs
Auth done right
Two building blocks, no shortcuts.
1. Never store raw passwords
Even if your database leaks, attackers should get hashes, not passwords.
Real code (production):
import bcrypt
hashed = bcrypt.hashpw(b"hunter2", bcrypt.gensalt(rounds=12))
bcrypt.checkpw(b"hunter2", hashed) # True
gensalt(rounds=12)= ~250 ms per hash. Slow on purpose — makes brute-force expensive.- Alternatives: argon2 (newer, resists GPU attacks better).
- Never: plain SHA / MD5 — instant to crack with a rainbow table.
2. JWT for stateless sessions
A JWT is three base64url pieces joined by .:
header.payload.signature
- header — algorithm (e.g. HS256).
- payload — claims:
sub(subject / user id),exp(expiry unix ts),iat(issued at). - signature — HMAC of
header.payloadwith your secret. Prevents tampering.
Real code:
import jwt
token = jwt.encode({"sub": "alice", "exp": time.time() + 3600}, SECRET, algorithm="HS256")
decoded = jwt.decode(token, SECRET, algorithms=["HS256"])
Things that bite
- Store JWTs in httpOnly cookies, not localStorage — XSS-safe.
- Short expiry (~1h) + refresh token pattern. Long-lived JWTs can't be revoked.
- Never trust JWT payload without verifying signature — attackers set
alg: noneif you're careless. - Rotate SECRET if it leaks. All existing tokens become invalid — a feature.
Try it
- Add an
iatclaim and check it's within the last minute. - Try to verify a tampered token — flip a char, watch the signature fail.