User Session
Data Entity
Description
Tracks active authentication sessions for users across the Mobile App and Admin Web Portal. Stores access token metadata, session origin, device info, and expiry. Supports session revocation by user or admin, rotating refresh token chains, and per-tenant isolation.
Data Structure
| Name | Type | Description | Constraints |
|---|---|---|---|
id |
uuid |
Primary key for the session record | PKrequiredunique |
user_id |
uuid |
Foreign key to the user who owns this session | required |
organization_id |
uuid |
Organization context for the session; null for Global Admins who have no org context at login | - |
auth_method |
enum |
Authentication method used to create this session | required |
access_token_jti |
string |
JWT ID (jti claim) of the current access token issued for this session; used for revocation checks | requiredunique |
client_type |
enum |
Which product client established this session | required |
device_name |
string |
Human-readable device name for session management UI (e.g. 'iPhone 15', 'Chrome on MacOS') | - |
device_fingerprint |
string |
Hashed device identifier for anomaly detection and binding refresh tokens to originating device | - |
ip_address |
string |
IP address at session creation; used for audit log and security dashboard | - |
user_agent |
string |
User-agent string of the client at session creation | - |
created_at |
datetime |
Timestamp when the session was established (login time) | required |
last_active_at |
datetime |
Timestamp of the last successful token refresh or API call; used for idle timeout enforcement | required |
expires_at |
datetime |
Absolute session expiry — session is invalid regardless of refresh activity after this point | required |
revoked_at |
datetime |
Timestamp when the session was explicitly revoked (logout, admin action, forced expiry); null if active | - |
revocation_reason |
enum |
Why the session was revoked | - |
is_active |
boolean |
Computed convenience flag: true when revoked_at IS NULL AND expires_at > NOW() | required |
support_access_grant_id |
uuid |
If this session was created under a time-bounded Global Admin support access grant, references the grant record | - |
biometric_bound |
boolean |
Whether this session has been unlocked via biometric (Face ID / fingerprint) on the mobile device; affects which sensitive flows require re-auth | required |
metadata |
json |
Extensible bag for product-specific session claims (e.g. role snapshot at login time, enabled module set hash) without polluting the core session schema | - |
Database Indexes
idx_user_sessions_user_id
Columns: user_id
idx_user_sessions_access_token_jti
Columns: access_token_jti
idx_user_sessions_user_id_is_active
Columns: user_id, is_active
idx_user_sessions_expires_at
Columns: expires_at
idx_user_sessions_organization_id
Columns: organization_id
idx_user_sessions_created_at
Columns: created_at
Validation Rules
expires_at_must_be_future
error
Validation failed
access_token_jti_unique
error
Validation failed
auth_method_client_type_compatibility
error
Validation failed
revoked_at_requires_reason
error
Validation failed
user_id_must_exist
error
Validation failed
organization_id_must_match_user_membership
error
Validation failed
ip_address_format
warning
Validation failed
Business Rules
single_active_session_per_client_type
A user may have at most one active session per client_type (mobile_app, admin_web_portal). Creating a new session for the same user+client_type invalidates the previous one to prevent silent multi-device token leakage.
global_admin_no_org_context
Sessions created by a Global Admin must have organization_id = NULL unless the session was established under a support_access_grant. Any attempt to set organization_id for a Global Admin without a grant must be rejected.
support_access_session_auto_revoke
Sessions linked to a support_access_grant must be automatically revoked when the grant's expiry date is reached or the grant is manually revoked by the organization. The revocation must be logged in the org's audit trail.
biometric_session_unlock_only
Biometric authentication (Face ID / fingerprint) may only set biometric_bound = true on an existing session established via email_password, bankid, vipps, or passkey. Biometric cannot create a new session from scratch — it unlocks an existing one.
mobile_token_secure_store
For mobile_app sessions, the access and refresh tokens must be stored in the platform's secure store (Flutter SecureStorage / Keychain). Sessions originating from mobile_app that show signs of insecure storage (e.g. plain preferences) must be immediately revoked.
admin_portal_http_only_cookie
Sessions for admin_web_portal clients must use HTTP-only cookies for token delivery. The session record exists in the database; the cookie is the transport mechanism.
idle_timeout_enforcement
If last_active_at has not been updated within the configured idle timeout window (e.g. 30 minutes for mobile, 15 minutes for admin portal), the session must be treated as expired even if expires_at has not been reached.
session_audit_on_revocation
Every session revocation (regardless of reason) must produce an audit log entry recording the user, organization, session id, revocation reason, and actor (self or admin).