Web Auth Models
File: api/nextango/apps/web_auth/models.py
Last Updated: 2026-07-09
Overview
web_auth defines three pure-Django models (models.Model, no Sanity sync) that back session-based authentication for the dashboard and storefront: WebSession tracks active sessions, OTPCode tracks one-time passwords, and SessionPermission defines which endpoints each session type may reach. Field names are snake_case throughout.
WebSession
Tracks an active web authentication session for dashboard or demo access, for both authenticated users and guests.
Base class: models.Model
| Field | Type | Description |
|---|---|---|
id | UUIDField (primary key) | UUID, generated on creation |
session_key | CharField(40), unique | Links the row to Django's session framework |
user | ForeignKey → User, nullable, CASCADE | Authenticated user; null for guest sessions. Related name web_sessions |
session_type | CharField(20), choices | demo or dashboard. Admin sessions are handled separately by AdminOTPAuthMiddleware |
is_guest | BooleanField, default False | True for a demo session with no user account |
email | EmailField, nullable | Guest email, used for OTP verification when there is no user |
cart_token_hash | CharField(64), nullable, unique, indexed | SHA-256 hash of a guest cart-session bearer token. A cookie-independent credential onto this session row, for guest cart operations in contexts where the session cookie does not round-trip |
created_at | DateTimeField, auto_now_add | Session creation timestamp |
expires_at | DateTimeField | Expiration timestamp. Defaults to 2 hours from creation for demo sessions and 7 days for dashboard sessions when not set explicitly |
last_activity | DateTimeField, auto_now | Updated on every request that validates the session |
ip_address | GenericIPAddressField, nullable | Client IP captured at session creation |
user_agent | TextField | Browser user agent string |
is_expired() returns True when expires_at has passed.
Serialized by WebSessionSerializer. Created, validated, and terminated by SessionService.
OTPCode
A one-time password code used for login, password recovery, email verification, and email change.
Base class: models.Model
| Field | Type | Description |
|---|---|---|
id | AutoField (primary key) | Default Django integer primary key |
email | EmailField, indexed | Recipient email address, not unique |
code | CharField(6) | 6-digit numeric code |
created_at | DateTimeField, auto_now_add | Creation timestamp |
expires_at | DateTimeField | Expiration timestamp. Defaults to 5 minutes from creation when not set explicitly |
verified | BooleanField, default False | True once the code has been consumed |
attempts | IntegerField, default 0 | Failed verification attempts; is_valid() returns False once this reaches 5 |
purpose | CharField(20), choices | Declared choices are login, password_recovery, verification. The views layer also creates OTPs with purpose='email_change', a value outside the declared choices |
is_expired() returns True when expires_at has passed. is_valid() returns True only when the code is unverified, unexpired, and has fewer than 5 attempts.
Serialized by OTPCodeSerializer, which excludes code. Generated and verified by OTPService.
SessionPermission
A database-driven permission rule that controls which endpoints a session type (demo or dashboard) may reach.
Base class: models.Model
| Field | Type | Description |
|---|---|---|
id | AutoField (primary key) | Default Django integer primary key |
session_type | CharField(20), choices | demo or dashboard |
endpoint_pattern | CharField(255) | Regex pattern matched against request.path |
http_methods | JSONField, default list | Allowed HTTP methods, for example ["GET", "POST"]. "*" allows any method |
description | TextField | Human-readable explanation of what the rule allows |
created_at | DateTimeField, auto_now_add | Creation timestamp |
updated_at | DateTimeField, auto_now | Last modification timestamp |
is_active | BooleanField, default True | Inactive rules are not enforced |
Serialized by SessionPermissionSerializer. Looked up by SessionService.get_permissions() and matched against the request path by WebSessionAuthMiddleware.