--- since: 1.1.1 --- # **AuthX — Data Model** --- ## **1. Overview** AuthX uses a relational persistence model centered around the authenticated identity. The persistence layer separates: - User identity - Refresh-token state - Authentication lifecycle state - Token revocation state The identity record is the primary source of truth for authentication, while refresh tokens provide the server-side state required for token rotation and revocation. Access tokens remain stateless and are not persisted. --- ## **2. Persistence Model** The core persistence relationship is: ```text UserIdentity │ │ 1 │ │ N ▼ RefreshToken ```` At a high level: ```text ┌─────────────────────────────┐ │ UserIdentity │ │ │ │ Identity / Credentials │ │ Account State │ │ Verification State │ │ SSO Identity │ │ Login Metadata │ └──────────────┬──────────────┘ │ │ 1 : N ▼ ┌─────────────────────────────┐ │ RefreshToken │ │ │ │ Token Identity │ │ JWT ID (JTI) │ │ Revocation State │ │ Expiration │ │ Creation Metadata │ └─────────────────────────────┘ ``` --- # **3. UserIdentity** `UserIdentity` represents the authenticated identity managed by AuthX. It is the primary authentication record and acts as the identity source of truth. ### **Core Identity Data** Typical identity attributes include: ```text id email username ``` ### **Credential Data** ```text password_hash ``` The password is never stored as plaintext. The stored password representation is used by the configured password-verification mechanism. ### **SSO Identity** SSO-linked identities are represented through: ```text sso_provider sso_id ``` This allows an identity to be associated with an external identity provider. ### **Account State** The identity also maintains account and verification state: ```text is_active is_verified is_staff is_superuser ``` ### **Lifecycle Metadata** ```text created_at updated_at deleted_at last_login ``` `deleted_at` supports the identity lifecycle without requiring immediate physical deletion of the underlying record. --- # **4. UserIdentity Indexing** Identity lookups are optimized around the fields used by authentication and SSO workflows. Important indexes include: ```text email sso_provider + sso_id is_active + deleted_at ``` The exact database index definition is owned by the AuthX migrations and should be treated as the authoritative schema. --- # **5. RefreshToken** `RefreshToken` represents server-side refresh-token state. Unlike access tokens, refresh tokens require persistence because AuthX must be able to determine whether a refresh token is still valid and whether it has been revoked. Core fields include: ```text id identity_id jti is_revoked expires_at created_at ``` --- ## **5.1 Identity Relationship** `identity_id` references: ```text user_identity.id ``` The relationship is: ```text UserIdentity │ │ 1 │ │ N ▼ RefreshToken ``` An identity can therefore have multiple refresh-token records. This supports multiple sessions/devices and token rotation. --- ## **5.2 JWT ID (JTI)** The `jti` field stores the JWT ID associated with the refresh token. It provides a server-side lookup key for refresh-token lifecycle operations such as: * Token validation * Rotation * Revocation * Session/token invalidation --- ## **5.3 Revocation** Refresh-token records contain: ```text is_revoked ``` This allows AuthX to invalidate a refresh token without relying exclusively on its expiration time. A token can therefore be: ```text Valid │ ├── Not expired └── Not revoked ``` or: ```text Invalid │ ├── Expired └── Revoked ``` --- # **6. Token Persistence Model** AuthX intentionally uses different persistence strategies for access and refresh tokens. ```text Authentication │ ┌────────────┴────────────┐ ▼ ▼ Access Token Refresh Token │ │ ▼ ▼ Stateless Stateful │ │ Not persisted Database record │ ┌────────┼────────┐ ▼ ▼ ▼ JTI Revoked Expiry ``` ### **Access Tokens** Access tokens are stateless. They are not stored in the AuthX database. Their validity is determined from the token itself and the configured authentication/verification rules. ### **Refresh Tokens** Refresh tokens are stateful. They are persisted because AuthX needs server-side state for: * Rotation * Revocation * Expiration tracking * Token lifecycle management --- # **7. Authentication Data Boundaries** The persistence model deliberately separates identity data from token lifecycle data. ```text ┌───────────────────────────────────────┐ │ AuthX Identity │ │ │ │ UserIdentity │ │ ├── Identity │ │ ├── Credentials │ │ ├── SSO │ │ ├── Verification │ │ └── Account State │ │ │ │ │ │ │ │ 1:N │ │ ▼ │ │ RefreshToken │ │ ├── JTI │ │ ├── Revocation │ │ ├── Expiration │ │ └── Lifecycle │ └───────────────────────────────────────┘ ``` This separation prevents token lifecycle state from becoming part of the core identity record. --- # **8. Data Lifecycle** A simplified identity lifecycle is: ```text Identity Created │ ▼ Email / Identity Verification │ ▼ Active Identity │ ├───────────────┐ ▼ ▼ Authentication SSO Authentication │ │ └───────┬───────┘ ▼ Token Issuance │ ┌─────┴─────┐ ▼ ▼ Access Token Refresh Token Stateless Persisted │ ┌──────┴──────┐ ▼ ▼ Rotate Revoke ``` The identity lifecycle and token lifecycle are therefore related but independently managed. --- # **9. Soft Deletion** The identity model includes: ```text deleted_at ``` This allows AuthX to represent a deleted/deactivated identity without necessarily removing the database record immediately. Authentication and identity lookups should respect the active/deleted state. The combination of: ```text is_active deleted_at ``` allows the application to distinguish between account state and deletion lifecycle. --- # **10. Data Integrity** The persistence layer should maintain the following invariants: 1. Each `UserIdentity` has a unique identity record. 2. SSO identity mappings are uniquely identifiable by provider and provider-specific identity. 3. Each `RefreshToken` belongs to an existing identity. 4. Revoked refresh tokens cannot be used as valid refresh credentials. 5. Expired refresh tokens cannot be used as valid refresh credentials. 6. Access tokens do not require database persistence. 7. Passwords are never persisted as plaintext. Database constraints and migrations are the final authority for the exact implementation of these rules. --- # **11. Security Considerations** Authentication data is security-sensitive. The persistence layer therefore follows these principles: * Passwords are stored only as password hashes. * Plaintext passwords must never be persisted. * Refresh-token state is persisted only where required for lifecycle control. * Access tokens are not persisted. * Token revocation state is maintained server-side. * Authentication records should not be exposed through unrestricted APIs. * Database credentials must remain outside source control. * Sensitive authentication data must not be written to application logs. --- # **12. Database Schema Ownership** The AuthX database schema is defined by the AuthX application's models and migrations. This document describes the **logical data model**, not a replacement for the migration history. When determining the exact current schema, use: ```text AuthX Models │ ▼ Django Migrations │ ▼ Database Schema ``` The migration state should always be treated as authoritative for deployed environments. --- # **13. Summary** AuthX's persistence model is centered around two core concepts: | Model | Responsibility | | -------------- | ---------------------------------------------------------------------- | | `UserIdentity` | Authentication identity, credentials, SSO, account and lifecycle state | | `RefreshToken` | Stateful refresh-token lifecycle, JTI, expiration and revocation | The fundamental relationship is: ```text UserIdentity 1 ───────── N RefreshToken ``` Access tokens remain stateless, while refresh tokens are persisted to support secure rotation and revocation. This design keeps the identity model independent from token lifecycle state while providing AuthX with the server-side controls required for secure authentication.