Rules Hub
Coding Rules Library
Rule priority, scope & exceptions
Use this to align rules with the senior-level structure (P0/P1/P2, scope, exceptions/tradeoffs).
Harden authentication and account recovery against takeover
Protect login and recovery flows with strong validation, rate limiting, secure tokens, and re-auth for sensitive actions.
Bad example
| 1 | app.post('/login', async (req, res) => { |
| 2 | const user = await db.user.findUnique({ where: { email: req.body.email } }); |
| 3 | if (!user) return res.status(401).json({ message: 'Invalid credentials' }); |
| 4 |
|
| 5 | // BAD: plaintext compare; no lockout; no rate limit |
| 6 | if (req.body.password !== user.password) { |
| 7 | return res.status(401).json({ message: 'Invalid credentials' }); |
| 8 | } |
| 9 |
|
| 10 | // BAD: weak token / no expiry validation elsewhere |
| 11 | const token = signJwt({ userId: user.id }, { expiresIn: '365d' }); |
| 12 | return res.json({ token }); |
| 13 | }); |
| 14 |
|
| 15 | app.put('/account/email', async (req, res) => { |
| 16 | // BAD: changes email without re-auth / password confirmation |
| 17 | await db.user.update({ where: { id: req.auth.userId }, data: { email: req.body.email } }); |
| 18 | res.json({ ok: true }); |
| 19 | }); |
Explanation (EN)
Weak password handling, missing anti-bruteforce protections, overly permissive token practices, and allowing sensitive changes without re-auth make account takeover easier.
Objašnjenje (HR)
Slabo rukovanje lozinkama, izostanak anti-bruteforce zaštite, previše permisivni tokeni i dopuštanje osjetljivih promjena bez re-auth-a olakšavaju preuzimanje računa.
Good example
| 1 | app.post('/login', rateLimitStrict, async (req, res) => { |
| 2 | const { email, password } = req.body; |
| 3 | const user = await db.user.findUnique({ where: { email } }); |
| 4 | if (!user) return res.status(401).json({ message: 'Invalid credentials' }); |
| 5 |
|
| 6 | const ok = await verifyPassword(password, user.passwordHash); |
| 7 | if (!ok) { |
| 8 | await registerFailedLoginAttempt(user.id); |
| 9 | return res.status(401).json({ message: 'Invalid credentials' }); |
| 10 | } |
| 11 |
|
| 12 | await clearFailedLoginAttempts(user.id); |
| 13 | const token = signJwt({ userId: user.id }, { expiresIn: '15m' }); |
| 14 | const refreshToken = await issueRefreshToken(user.id); |
| 15 |
|
| 16 | return res.json({ token, refreshToken }); |
| 17 | }); |
| 18 |
|
| 19 | app.put('/account/email', requireReAuth, async (req, res) => { |
| 20 | const { newEmail } = req.body; |
| 21 | await db.user.update({ where: { id: req.auth.userId }, data: { email: newEmail } }); |
| 22 | res.json({ ok: true }); |
| 23 | }); |
Explanation (EN)
Use strong password hashing, strict anti-bruteforce controls, short-lived access tokens with validated expiry, and require re-authentication for sensitive operations (email/password/2FA changes).
Objašnjenje (HR)
Koristi snažno hashiranje lozinki, strogu anti-bruteforce zaštitu, kratkotrajne access tokene s provjerenim istekom i zahtijevaj re-autentifikaciju za osjetljive operacije (email/lozinka/2FA promjene).
Notes (EN)
Also: never send auth tokens/passwords in URLs; reject unsigned/weak JWTs; validate issuer/audience/expiry; treat forgot/reset like login (rate limit + lockout); implement weak-password checks; prefer MFA where possible; be careful with GraphQL batching bypassing rate limits.
Bilješke (HR)
Također: nikad ne šalji auth tokene/lozinke u URL-u; odbij unsigned/slabo potpisane JWT-e; validiraj issuer/audience/expiry; tretiraj forgot/reset kao login (rate limit + lockout); provjeri slabe lozinke; uvedi MFA gdje možeš; pazi da GraphQL batching ne zaobiđe rate limiting.