Session
Data Entity
Description
Represents an authenticated user session in the Meander platform. Each login event creates one session record that anchors the entire token chain lifecycle. Short-lived JWTs carry the session ID as a claim; rotating refresh tokens (refresh_tokens child records) silently extend the session across access token expiry. Sessions terminate via user sign-out, idle timeout, hard expiry, or administrator-initiated revocation. The auth module owns session state exclusively — no product data, role semantics, or authorization logic is stored here.
Data Structure
| Name | Type | Description | Constraints |
|---|---|---|---|
id |
uuid |
Primary key. Unique session identifier embedded in every access token as the `sid` claim, enabling per-session revocation checks without hitting the database on every request (checked only on token refresh). | PKrequiredunique |
user_id |
uuid |
FK → users.id. The authenticated user who owns this session. All refresh tokens under this session inherit this ownership. | required |
org_id |
uuid |
FK → organizations.id. Organization context resolved at login time from the user's primary membership. Null for global admins who have no org context. Included in access token claims for tenant-scoped API enforcement. | - |
auth_method |
enum |
Authentication mechanism used to initiate this session. Biometric unlock is not listed here — it reuses an existing session rather than creating a new one. | required |
platform |
enum |
Client platform that opened this session. Shown on the Active Sessions admin page and used for security anomaly detection. | required |
device_id |
string |
Opaque device fingerprint supplied by the mobile client (Flutter platform channel). Null for web sessions. Used to correlate multiple sessions from the same physical device. | - |
user_agent |
string |
HTTP User-Agent header captured at login. Displayed on the Active Sessions admin page so administrators can identify suspicious clients. | - |
ip_address |
string |
Client IP address (IPv4 or IPv6, max 45 chars) at login time. Used by the Security Metrics Service for anomaly detection and geographic risk scoring. | - |
is_revoked |
boolean |
Hard revocation flag. When true, all refresh_tokens rows with this session_id are also logically invalidated. Access tokens already in flight remain valid until their short TTL expires (no token blocklist required). | required |
revoked_at |
datetime |
UTC timestamp of revocation. Null while session is active. Set atomically with is_revoked=true. | - |
revoked_by_user_id |
uuid |
user_id of the administrator who force-revoked this session via the Active Sessions admin page. Null for user-initiated sign-out or system expiry. | - |
revocation_reason |
enum |
Categorized reason for revocation. Written to the audit log on revocation events. | - |
expires_at |
datetime |
Hard expiry for the entire session chain. After this datetime no refresh token belonging to this session may be exchanged, regardless of is_revoked state. Typically 90 days from creation for mobile, 24 hours for web. | required |
last_active_at |
datetime |
Updated on every successful token refresh. Used to enforce an idle-session timeout policy (e.g. revoke if inactive for 30 days) via a background cleanup job. | required |
module_set_snapshot |
json |
Snapshot of the tenant's enabled area/module IDs at login time (e.g. ["activity-registration", "expense-reimbursement"]). Embedded in access token claims so the mobile app can bootstrap navigation without a separate API call. Refreshed on the next token rotation if the org's module configuration changes. | - |
created_at |
datetime |
UTC timestamp of the login event that created this session. | required |
Database Indexes
idx_sessions_user_id
Columns: user_id
idx_sessions_user_id_active
Columns: user_id, is_revoked, expires_at
idx_sessions_org_id
Columns: org_id
idx_sessions_expires_at
Columns: expires_at
idx_sessions_last_active_at
Columns: last_active_at
Validation Rules
expires_at_in_future
error
Validation failed
revocation_fields_consistent
error
Validation failed
auth_method_platform_compatibility
error
Validation failed
user_id_references_active_user
error
Validation failed
ip_address_format
warning
Validation failed
module_set_snapshot_valid_json
warning
Validation failed
Business Rules
single_active_session_per_device
When a new session is created from the same device_id as an existing active session, the old session is revoked with reason 'token_rotation_failure' before the new one is inserted. Prevents ghost sessions accumulating on re-installs.
session_inherits_org_context
org_id is resolved from the user's primary organization membership at login and is immutable for the lifetime of the session. If the user's membership changes, the change takes effect on next login, not mid-session.
cascade_revoke_refresh_tokens
When is_revoked is set to true on a session, all refresh_tokens rows where session_id = this session's id must be invalidated in the same transaction. No dangling active refresh tokens may exist under a revoked session.
admin_revocation_requires_audit
Any revocation where revoked_by_user_id is non-null (admin-forced) must produce an audit log entry via the Audit Service before the transaction commits.
module_set_refreshed_on_rotation
On each token refresh, auth-service compares the stored module_set_snapshot against the org's current module configuration. If different, the snapshot is updated and the new access token carries the updated module set.
hard_expiry_non_extendable
expires_at is set once at creation and is never extended, even for highly active sessions. Mobile sessions expire after 90 days; web sessions after 24 hours. Users must re-authenticate after expiry.
account_deactivation_triggers_revocation
When a user account is deactivated (via admin user management), all active sessions for that user_id are batch-revoked with reason 'account_deactivated'.
global_admin_no_org_context
Sessions created for users with the Global Admin role must have org_id = null. Any attempt to set an org_id for a Global Admin session is rejected.