Django's built-in authentication is solid but insufficient for production SaaS. Here are the critical additions required.
Password security:
- Argon2 hashing: Switch from Django's default PBKDF2 to Argon2id — the winner of the Password Hashing Competition.
PASSWORD_HASHERS = ["django.contrib.auth.hashers.Argon2PasswordHasher", ...]. Installargon2-cffi. Argon2id is resistant to both GPU and side-channel attacks. - Password validation: Enable all Django validators plus add
django-password-validatorsfor breach database checking (checks against Have I Been Pwned's 800M+ compromised passwords via k-anonymity API — no password leaves your server). - Rate limiting:
django-axes— locks out IP after 5 failed login attempts for 30 minutes. Configurable per-user and per-IP lockout. Essential to prevent credential stuffing attacks.AXES_FAILURE_LIMIT = 5,AXES_COOLOFF_TIME = timedelta(minutes=30).
Multi-factor authentication (MFA):
- Use
django-allauthwith TOTP (Time-based One-Time Password) support. Users scan a QR code with Google Authenticator, Authy, or 1Password. - Enforce MFA for admin users and optionally for all users. Store recovery codes (10 single-use codes generated at MFA setup).
- WebAuthn/FIDO2 support via
django-fido2for hardware security keys (YubiKey). Phishing-resistant authentication. - Implementation cost: EUR 800-1,500 for TOTP MFA. EUR 1,500-2,500 for TOTP + WebAuthn.
Session security:
SESSION_COOKIE_SECURE = True(HTTPS only)SESSION_COOKIE_HTTPONLY = True(no JavaScript access)SESSION_COOKIE_SAMESITE = "Lax"(CSRF protection)SESSION_COOKIE_AGE = 86400(24-hour session timeout for SaaS)- Implement session invalidation on password change:
update_session_auth_hash(request, user) - Track active sessions: store IP, user agent, last activity. Allow users to revoke sessions from settings page ("Logged in on: Chrome, Berlin — 2 hours ago").
Role-based access control (RBAC):
- Use
django-guardianfor object-level permissions ordjango-rulesfor predicate-based permissions. - Typical SaaS roles: Owner (full access + billing), Admin (team + settings management), Member (standard access), Viewer (read-only), Guest (limited access to shared items).
- Implement permission checks in DRF views:
class ProjectViewSet: permission_classes = [IsAuthenticated, HasProjectAccess]. Never rely solely on frontend hiding UI elements — always enforce on backend.