5.9 KiB
5.9 KiB
Identity and Authentication
Purpose
Document how user identity, JWT handling, API keys, and session flows work, including middleware and validation rules.
Code Locations (exact paths)
- JWT utilities:
backend/igny8_core/auth/utils.py - Account context middleware:
backend/igny8_core/auth/middleware.py - DRF authentication classes:
backend/igny8_core/api/authentication.py - DRF settings for auth/throttle:
backend/igny8_core/settings.py - User model and roles:
backend/igny8_core/auth/models.py - Auth URLs and views:
backend/igny8_core/auth/urls.py,backend/igny8_core/auth/views.py
High-Level Responsibilities
- Support multiple auth mechanisms: API key (WordPress bridge), JWT bearer tokens, session auth without CSRF for APIs, and basic auth fallback.
- Populate tenant/site context alongside user identity so downstream viewsets enforce isolation.
- Enforce active account/plan presence before serving protected endpoints (except admin/auth routes).
Detailed Behavior
- Authentication order (DRF
DEFAULT_AUTHENTICATION_CLASSESinsettings.py): API key → JWT → CSRF-exempt session → basic auth. The first class that authenticates setsrequest.user;request.accountmay also be set by API key or JWT. - API Key flow (
APIKeyAuthentication): expectsAuthorization: Bearer <api_key>that is not JWT-like; finds an activeSitewithwp_api_key, loads itsaccount, and selects an active user (owner preferred, else any active developer/owner/admin). Setsrequest.accountandrequest.site. Rejects short/invalid keys; returns an auth failure if no active user exists. - JWT flow (
JWTAuthentication): expectsAuthorization: Bearer <jwt>; decodes viaauth.utils.decode_token; only accepts tokens withtype == access. RetrievesUserbyuser_id; optionalaccount_idis resolved toAccountand set onrequest.account. Invalid/expired tokens fall through to other auth classes. - Session flow (
CSRFExemptSessionAuthentication): uses Django session cookies without CSRF enforcement for API calls. - Basic auth: last resort; does not set tenant context.
- Token utilities (
auth/utils.py) generate and decode access/refresh tokens using expiries from settings (JWT_ACCESS_TOKEN_EXPIRY,JWT_REFRESH_TOKEN_EXPIRY), embeddinguser_id,account_id,email, issued/expiry timestamps, and tokentype. - Middleware (
AccountContextMiddleware) runs on every request except admin/auth paths: refreshes session users from DB to pick up current account/plan, validates presence of an active plan, setsrequest.account, and logs out session users when invalid. For JWT-bearing requests it decodes the token directly and setsrequest.account. If account/plan is missing or inactive, it returns JSON withsuccess=falseand appropriate HTTP status.
Data Structures / Models Involved (no code)
UserwithroleandaccountFKs inauth/models.py.Accountwith plan and billing fields; plan status is used for access gating.Sitewithwp_api_keyfor API key auth;SiteUserAccessfor per-site grants.PasswordResetTokenmodel for password reset flows.- JWT payload fields:
user_id,account_id,email,exp,iat,type.
Execution Flow
- Middleware step:
AccountContextMiddlewaredeterminesrequest.account(session or JWT) and validates plan status; skips admin/auth routes. - DRF auth step: API key/JWT/session/basic authenticators run in order, potentially setting
request.account(API key/JWT) andrequest.site(API key). - Viewsets then apply role/permission checks and tenant/site/sector filtering via base classes in
api/base.py.
Cross-Module Interactions
- All module viewsets rely on
request.userandrequest.accountset by the auth stack. Site-aware modules can readrequest.sitewhen API key auth is used. - Role helpers (
is_admin_or_developer,is_system_account_user) influence filtering bypass in base viewsets.
State Transitions (if applicable)
- JWT lifetimes: access tokens default to 15 minutes; refresh tokens to 30 days (configurable in settings).
- Session users are refreshed on each request to pick up plan/account changes.
- Password reset tokens track expiry and usage via
expires_atandusedflags.
Error Handling
- Middleware returns JSON errors for missing account or inactive plan and logs out session users in those cases.
- Invalid/expired JWTs cause the JWT authenticator to return
None, allowing other auth methods; decoding errors raiseInvalidTokenErrorin utilities. - API key auth raises an auth failure when no active user is available for the resolved account.
Tenancy Rules
request.accountis set early; base viewsets enforce account filtering unless user has admin/developer/system-account privileges.- API key auth also sets
request.sitefor integration contexts; site/sector filtering occurs inSiteSectorModelViewSet.
Billing Rules (if applicable)
- Active plan is required for access (middleware enforces). Credit debits/charges are handled in billing modules, not in the auth layer.
Background Tasks / Schedulers (if applicable)
- Token generation/validation is synchronous. Background tasks should receive explicit user/account identifiers in their payloads when invoked.
Key Design Considerations
- Authentication stack is ordered to give integration API keys precedence, then JWT for app clients, then session for browser-based flows.
- Tenant context must be established before view logic; do not move or remove
AccountContextMiddleware. - Expiry durations and JWT secrets are centrally configured in
settings.py.
How Developers Should Work With This Module
- Use token helpers from
auth/utils.pywhen issuing tokens; do not handcraft JWTs. - Mount new auth-sensitive endpoints under existing routers and rely on DRF auth classes instead of custom header parsing.
- Ensure new features that require site context can work with API key auth by checking
request.site. - Keep plan enforcement in place; bypass only for admin/system routes when justified.