Skip to main content

accounts app

User accounts, password management, email verification, and GDPR-compliant data export / account deletion.

Models (4)

  • User — extended Django user with UUID PK, email-as-username, encrypted phone
  • UserEmail — secondary verified emails for one user; SSO uses these for matching
  • UserConsent — captures consent template acceptances (privacy / terms / marketing / analytics)
  • DataExport — async data-export job state (status, S3 URL, expires_at)

Key endpoints

URLPurpose
POST /api/auth/register/Self-signup with email + password
POST /api/auth/login/Email + password → sets JWT cookies
POST /api/auth/logout/Clears cookies, blacklists refresh token
GET /api/auth/me/Current user profile
PATCH /api/auth/me/Update first/last name, phone
POST /api/auth/me/password/Change password
POST /api/auth/me/emails/add/Add a secondary email
POST /api/auth/me/emails/verify/Verify a secondary email via token
POST /api/auth/password-reset/request/Request reset email
POST /api/auth/password-reset/confirm/Submit new password with token
POST /api/auth/me/export/Trigger GDPR data export (Celery → S3)
POST /api/auth/me/delete/Request account deletion (30-day grace period)
POST /api/auth/admin/password-reset/Admin-initiated password reset (org admin only)

Permissions

  • IsAuthenticated — most endpoints
  • AllowAny — register, login, password reset request (rate-throttled)
  • IsNationalAdmin — admin password reset

Background tasks

  • send_email_verification(user_email_id) — sends verification email
  • send_temporary_password_notification(user_id, temp_password) — admin reset flow
  • export_user_data(data_export_id) — bundles all user data, gzips, uploads to S3, generates presigned URL valid for 7 days

External integrations

  • AWS S3 (data export storage via boto3)
  • Email backend (configured at apps.platform.PlatformEmailConfig)

Signals

  • post_save on User — auto-creates UserEmail row from primary email

Notable patterns

Account deletion grace period

POST /api/auth/me/delete/ doesn't immediately delete. It:

  1. Sets User.deletion_requested_at = now()
  2. Sends confirmation email with a "cancel" link
  3. After 30 days, prune_pending_deletions task scrubs the account

Cancelling: signing in within 30 days clears deletion_requested_at.

Password hashing

Production uses Django's default PBKDF2 with 870K iterations. Tests override to MD5 via PASSWORD_HASHERS to keep tests fast.

Throttling

EndpointThrottle
register/account_request (3/hour prod)
login/, logout/auth (10/min prod)
password-reset/request/password_reset (5/hour prod)
admin/password-reset/admin_password_reset_target (10/hour prod)

Code paths

  • Models: backend/apps/accounts/models.py
  • Views: backend/apps/accounts/views.py
  • Serializers: backend/apps/accounts/serializers.py
  • URLs: backend/apps/accounts/urls.py
  • Tasks: backend/apps/accounts/tasks.py