Auth System Checklist

The essential playbook for implementing auth system checklist in your SaaS.

Use this checklist before launch or after major auth changes. It covers the minimum production requirements for a small SaaS auth system: secure credential handling, session/token design, account recovery, email verification, route protection, cookie settings, abuse controls, logging, and deployment-specific checks.

Quick Fix / Quick Setup

Auth System Checklist

  • Passwords hashed with bcrypt/argon2 only
  • SECRET_KEY and auth secrets stored in env vars
  • Secure cookies enabled in production
  • CSRF protection enabled for session-based auth
  • JWT expiry/rotation configured if using tokens
  • Email verification flow works end-to-end
  • Password reset tokens expire and are single-use
  • Protected routes enforce auth and roles
  • Rate limiting on login/register/reset endpoints
  • Logout invalidates session/token correctly
  • OAuth redirect URIs set for production domain
  • Auth events logged without storing secrets
  • Test user signup/login/reset from production domain
  • Session persistence verified behind proxy/HTTPS
  • Admin accounts protected with strong passwords/2FA if supported

Use this as a release gate. If any item is unchecked, treat auth as not production-ready.

Quick setup

  • Define your auth model first:
    • session-based auth for server-rendered apps
    • JWT access + refresh tokens for API/mobile-heavy apps
  • Store SECRET_KEY, JWT signing keys, OAuth secrets, SMTP credentials, and app base URLs in environment variables only.
  • Enable HTTPS in production before validating cookies, OAuth callbacks, and secure session behavior.
  • Set cookie flags correctly:
    • Secure=true
    • HttpOnly=true
    • SameSite=Lax or Strict unless cross-site flow requires otherwise
  • Hash passwords with bcrypt or Argon2.
  • Require email verification for new accounts if account ownership matters.
  • Make password reset tokens short-lived and single-use.
  • Add rate limits to login, register, reset, and verification resend endpoints.
  • Verify route protection on both frontend and backend.
  • Test the full auth flow on the real production domain, not only localhost or staging.
register
verify
login
session refresh
logout
reset password

Process Flow

What’s happening

Auth failures in production usually come from environment mismatches, cookie misconfiguration, broken proxy/HTTPS handling, incorrect redirect URLs, or missing backend authorization checks.

A launch-ready auth system must handle the full account lifecycle:

  • register
  • verify email
  • login
  • resume session or refresh token
  • logout
  • password reset
  • role checks
  • abuse prevention

Production auth issues often appear only after deployment because domains, TLS, proxies, and browser cookie policies differ from local development.

Checklist-driven validation reduces common launch regressions:

  • login loops
  • invalid sessions
  • broken OAuth callbacks
  • unprotected admin endpoints
  • reset links pointing to the wrong domain

Step-by-step implementation

1) Inventory auth scope

List exactly what your app supports:

  • email/password login
  • registration
  • email verification
  • password reset
  • session auth or JWT auth
  • OAuth/social login
  • RBAC/admin roles
  • billing/admin sensitive actions

Do not ship partial protection by assumption.

2) Verify secrets and environment variables

All auth secrets must come from env vars and must differ across dev, staging, and production.

bash
printenv | grep -E 'SECRET|JWT|AUTH|APP_URL|FRONTEND|API|OAUTH'

Minimum expected variables:

env
APP_URL=https://yourdomain.com
API_URL=https://yourdomain.com
FRONTEND_URL=https://yourdomain.com

SECRET_KEY=replace_me
JWT_SECRET=replace_me
SESSION_SECRET=replace_me

GOOGLE_CLIENT_ID=replace_me
GOOGLE_CLIENT_SECRET=replace_me

SMTP_HOST=replace_me
SMTP_USER=replace_me
SMTP_PASS=replace_me

Checks:

  • no hardcoded secrets in source
  • no dev values reused in prod
  • no accidental secret rotation during deploy

3) Review password storage

Requirements:

  • bcrypt or Argon2 only
  • per-password salt handled by library
  • no plaintext storage
  • no reversible encryption
  • no unsalted hash algorithms like raw SHA256/MD5

Example guidance:

js
// Node.js bcrypt example
const bcrypt = require("bcrypt");
const hash = await bcrypt.hash(password, 12);
const ok = await bcrypt.compare(inputPassword, hash);
js
// Node.js argon2 example
const argon2 = require("argon2");
const hash = await argon2.hash(password);
const ok = await argon2.verify(hash, inputPassword);

Checks:

  • new registrations hash correctly
  • password changes hash correctly
  • imports/migrations do not bypass hashing

4) Validate registration flow

Registration must handle:

  • email normalization
  • duplicate account detection
  • password strength validation
  • optional disposable email policy
  • verification token creation

Checks:

  • User@Example.com and user@example.com do not create duplicate accounts unintentionally
  • weak passwords are rejected
  • registration endpoint is rate-limited
  • signup response does not leak internal state

5) Validate email verification flow

Verification must work end-to-end on the production domain.

Checks:

  • token generated securely
  • token expires
  • token is one-time use
  • verification link uses correct APP_URL / frontend URL
  • resend verification is rate-limited
  • already-verified users handled cleanly

Test:

  • create new user in production
  • open real email
  • click verification link
  • confirm account state changes in DB
  • confirm verified user can access required features

6) Validate password reset flow

Minimum requirements:

  • request endpoint does not reveal whether user exists
  • reset token expires
  • reset token is single-use
  • reset link uses production domain
  • new password is hashed
  • previous reset token becomes invalid after use

Recommended extra check:

  • revoke active sessions after password reset if your app supports it

Example generic reset response:

json
{
  "message": "If the account exists, a password reset link has been sent."
}

7) Check login behavior

Verify:

  • rate limiting on failed attempts
  • generic error messages
  • correct session or token issuance
  • optional audit log of successful and failed login attempts
  • no password or token values logged

Example rate limit targets:

  • /api/login
  • /api/register
  • /api/password-reset/request
  • /api/password-reset/confirm
  • /api/email/verify/resend

8) Check logout behavior

Logout must invalidate auth state correctly.

For session auth:

  • delete server-side session
  • expire auth cookie

For JWT-based auth:

  • remove refresh token from store
  • rotate or revoke token if your architecture supports revocation
  • clear client storage if used
  • ensure protected endpoints reject old auth state

9) Review session settings

For cookie/session auth, verify:

  • Secure=true in production
  • HttpOnly=true
  • SameSite=Lax or Strict unless required otherwise
  • correct Domain and Path
  • explicit expiration/idle timeout
  • remember-me behavior is intentional
  • session store is persistent and shared when scaling
  • proxy trust is configured if behind load balancer/reverse proxy

Typical failure: app thinks requests are HTTP, so secure cookies do not behave correctly.

10) Review JWT settings if used

If using JWTs, verify:

  • short access token TTL
  • refresh token rotation
  • signing algorithm configured explicitly
  • iss and aud validated
  • token expiration enforced
  • invalidation strategy exists where needed
  • server time is correct

Safe local decode command:

bash
python -c "import jwt,sys; print(jwt.decode(sys.argv[1], options={'verify_signature': False}))" '<token>'

11) Validate backend protection

Every protected endpoint must enforce auth server-side.

Check:

  • private API routes reject anonymous requests
  • role checks protect admin actions
  • billing and internal actions require authorization
  • frontend route guards are not the only control

This is the most common production auth mistake.

For implementation patterns, see:

12) Test OAuth providers in production

Verify for each provider:

  • authorized redirect URI matches production exactly
  • callback handler works over HTTPS
  • state validation enabled
  • account linking rules are defined
  • missing-email provider edge cases handled
  • logout behavior understood if provider session persists

Debug commands:

bash
curl -I -L https://yourdomain.com/auth/google/login

13) Add abuse controls

Apply rate limiting and anti-abuse controls to:

  • login
  • registration
  • verification resend
  • password reset request
  • password reset confirm
  • OAuth start endpoints

At minimum, limit by IP. Better: combine IP + email/user fingerprint + request ID logging.

14) Log auth events safely

Log enough to debug, but never log secrets.

Good auth log fields:

  • event type
  • timestamp
  • user ID if known
  • email hash or normalized identifier if needed
  • IP
  • request ID
  • user agent
  • result code

Do not log:

  • passwords
  • reset tokens
  • JWTs
  • session IDs
  • OAuth client secrets
  • raw authorization headers

15) Run production smoke tests

Run all auth flows from the real production domain:

  • register
  • verify email
  • login
  • page refresh / session resume
  • protected route access
  • password reset request
  • password reset confirm
  • logout
  • repeat on desktop and mobile browser

Useful commands:

bash
curl -I https://yourdomain.com/login
curl -v https://yourdomain.com/api/me
curl -X POST https://yourdomain.com/api/login \
  -H 'Content-Type: application/json' \
  -d '{"email":"user@example.com","password":"testpass"}'

Common causes

  • SECRET_KEY or JWT signing key changed unexpectedly, invalidating sessions or tokens.
  • Cookies not marked Secure in HTTPS production, or SameSite blocks expected flow.
  • Proxy headers not trusted, causing app to think requests are HTTP instead of HTTPS.
  • OAuth redirect URI mismatch between provider dashboard and production domain.
  • Session storage not shared or persisted correctly across deploys or multiple instances.
  • Password reset or verification links using localhost or the wrong APP_URL.
  • Protected routes enforced in frontend only, not in backend API handlers.
  • CSRF protection missing or misconfigured for session-based auth.
  • JWT tokens missing proper expiration, audience, issuer, or rotation handling.
  • Login or reset endpoints exposed without rate limiting.
  • Email delivery failure prevents verification or reset completion.
  • Role checks missing on admin, billing, or internal endpoints.

Debugging tips

Check production env and auth config:

bash
printenv | grep -E 'SECRET|JWT|AUTH|APP_URL|FRONTEND|API|OAUTH'

Inspect headers and cookie behavior:

bash
curl -I https://yourdomain.com/login
curl -v https://yourdomain.com/api/me

Test login endpoint directly:

bash
curl -X POST https://yourdomain.com/api/login \
  -H 'Content-Type: application/json' \
  -d '{"email":"user@example.com","password":"testpass"}'

Test OAuth redirect chain:

bash
curl -I -L https://yourdomain.com/auth/google/login

Decode JWT locally without verifying signature:

bash
python -c "import jwt,sys; print(jwt.decode(sys.argv[1], options={'verify_signature': False}))" '<token>'

Inspect proxy and app logs:

bash
grep -Ei 'auth|login|logout|reset|verify|oauth|csrf|session' /var/log/nginx/access.log
grep -Ei 'auth|login|logout|reset|verify|oauth|csrf|session|error' /var/log/nginx/error.log
journalctl -u your-app.service -n 200 --no-pager
docker logs --tail 200 your-app-container

Additional checks:

  • inspect browser devtools for blocked cookies and failed redirects
  • verify server time sync if tokens are immediately expired
  • check whether deploys are wiping in-memory session stores
  • compare reverse proxy logs with app logs for the same request ID

For broader hardening and release validation, also review:

Checklist

  • Passwords hashed with bcrypt or Argon2
  • No plaintext passwords, tokens, or secrets stored or logged
  • Auth secrets and OAuth credentials stored in environment variables only
  • HTTPS enabled in production
  • Secure and HttpOnly cookie flags enabled where applicable
  • SameSite configured correctly for your auth flow
  • CSRF protection enabled for session-based auth
  • Session expiration and idle timeout configured
  • JWT expiry and refresh strategy configured if using tokens
  • Email verification works end-to-end on production domain
  • Password reset tokens are expiring and single-use
  • Reset request flow does not reveal whether a user exists
  • Protected API and page routes enforce authentication server-side
  • Role and permission checks protect admin and sensitive actions
  • Rate limiting enabled on login, register, reset, and verification endpoints
  • OAuth redirect URIs configured for production
  • Logout properly invalidates sessions or tokens
  • Session behavior verified across refreshes, subdomains, and proxies
  • Auth event logs enabled without exposing sensitive values
  • Manual smoke test completed for register, verify, login, reset, and logout

Product CTA

Use this page as a production release gate for auth changes.

If you maintain a small SaaS, convert this checklist into:

  • deploy-blocking release criteria
  • CI/CD validation steps
  • smoke-test scripts
  • incident review checks after auth-related changes

Use the same checklist model across auth, payments, security, and deployment so production quality is repeatable, not manual.

Relevant next checklists:

Related guides

FAQ

What should I verify first before launch?

Verify password hashing, cookie or token settings, route protection, email verification, password reset, logout behavior, and production-domain testing over HTTPS.

Is frontend route protection enough?

No. Every protected backend endpoint must enforce authentication and authorization independently of the frontend.

What breaks most often after deployment?

Cookie security settings, wrong callback URLs, missing proxy trust, broken email links, and non-persistent session storage.

Should auth secrets ever change?

Only through a controlled rotation process. Unplanned changes can invalidate all sessions or tokens immediately.

Do small SaaS apps need rate limiting on auth endpoints?

Yes. Login, register, reset, and verification resend endpoints should all have abuse protection in production.

Final takeaway

An auth system is production-ready only when the full user lifecycle works under real deployment conditions:

  • HTTPS
  • real domains
  • proxies
  • email delivery
  • cookie policy
  • backend authorization enforcement

Use this checklist as a release gate, not just documentation. Auth regressions are easier to prevent than to debug after launch.