Session
Data Entity
Description
Represents an active authenticated session for a user, tracking login method, device, and session lifetime. Sessions are created on successful authentication and invalidated on logout, token expiry, or forced revocation by an administrator. Provides the audit trail for login events.
Data Structure
| Name | Type | Description | Constraints |
|---|---|---|---|
id |
uuid |
Globally unique session identifier, generated server-side on session creation | PKrequiredunique |
user_id |
uuid |
Foreign key referencing the users table; identifies which user owns this session | required |
login_method |
enum |
The authentication method used to establish this session. Determines which identity provider was invoked and shapes token refresh behavior. | required |
device_info |
json |
Structured metadata about the client device: platform (ios|android|web), OS version, app version, and a stable device fingerprint derived from hardware identifiers. Used for audit display and concurrent session management. | required |
ip_address |
string |
IPv4 or IPv6 address of the client at session creation time. Stored for security audit purposes. Nullable for privacy-sensitive login flows. | - |
user_agent |
string |
HTTP User-Agent string captured at session creation. Supplements device_info for audit trail completeness. | - |
created_at |
datetime |
UTC timestamp of when this session was established via successful authentication. Immutable after creation. | required |
expires_at |
datetime |
UTC timestamp after which this session is considered expired and must be rejected. Set at creation based on login_method: longer for biometric, shorter for email_password. Must be strictly greater than created_at. | required |
last_active_at |
datetime |
UTC timestamp of the most recent API request authenticated by this session. Updated on every authenticated request via JWT middleware. Used to detect inactive sessions and for session sliding expiry policies. | - |
invalidated_at |
datetime |
UTC timestamp when this session was explicitly invalidated (logout, admin revocation, password change, security event). NULL means session is still potentially active. Non-NULL means session is permanently rejected regardless of expires_at. | - |
invalidation_reason |
enum |
The reason this session was terminated. Only populated when invalidated_at is non-NULL. Required when invalidated_at is set. | - |
organization_id |
uuid |
The organization context active at the time of session creation. Matches the user's selected organization during onboarding or org-switch. Used for multi-tenancy scoping during session validation. | required |
association_id |
uuid |
The specific local association context active when the session was created, if applicable. Nullable for global administrators who are not tied to a single association. | - |
role_at_creation |
enum |
The user role resolved and embedded in the JWT at session creation time. Stored here for audit and to detect role changes that occurred during an active session. | required |
biometric_enrolled |
boolean |
Whether the user enrolled biometric authentication (Face ID / fingerprint) during or after this session. Set to true when biometric setup completes. Drives whether biometric_auth_service may use this session's refresh token. | required |
Database Indexes
idx_session_user_id
Columns: user_id
idx_session_user_active
Columns: user_id, invalidated_at
idx_session_expires_at
Columns: expires_at
idx_session_created_at
Columns: created_at
idx_session_login_method
Columns: login_method
idx_session_organization_id
Columns: organization_id
Validation Rules
user_id_must_reference_existing_user
error
Validation failed
login_method_enum_strict
error
Validation failed
device_info_json_schema
error
Validation failed
invalidation_reason_required_with_invalidated_at
error
Validation failed
ip_address_format
error
Validation failed
organization_id_matches_user_membership
error
Validation failed
association_id_consistent_with_organization
error
Validation failed
role_at_creation_consistent_with_user_roles
error
Validation failed
Business Rules
session_created_only_on_successful_auth
A Session record may only be inserted after the authentication provider (email/password, BankID, Vipps) has returned a verified success response. Failed login attempts must not produce session rows.
expires_at_must_be_future
expires_at must always be strictly after created_at. The expiry window depends on login_method: email_password (8 hours), bankid/vipps (24 hours), biometric (30 days sliding).
invalidated_at_is_terminal
Once invalidated_at is set on a session, no further authentication operations may succeed using tokens derived from that session. This state is permanent and cannot be reversed.
logout_invalidates_session
When a user explicitly logs out, the current session's invalidated_at must be set to now() and invalidation_reason set to 'logout'. All associated auth_token records must be revoked simultaneously within the same transaction.
admin_revocation_invalidates_all_user_sessions
When an Organization Administrator or Global Administrator deactivates a user, all active sessions for that user must be invalidated with reason 'admin_revocation'. This prevents deactivated users from continuing to use the app on an existing session.
biometric_requires_prior_full_auth_session
Biometric authentication (login_method: biometric) can only establish a new session if the user previously completed a full BankID, Vipps, or email/password session from which a refresh token was stored. Pure biometric-only initial login is prohibited.
role_change_invalidates_active_sessions
If a user's role assignment changes (e.g., promoted from peer_mentor to coordinator), all existing sessions where role_at_creation differs from the new role must be invalidated with reason 'security_event', forcing re-authentication to issue a new JWT with correct role claims.
last_active_at_updated_on_authenticated_request
Every authenticated API request that passes JWT validation must update last_active_at to the current UTC time. This provides an accurate activity signal for inactive session cleanup jobs.
max_concurrent_sessions_per_user
A user may not exceed 5 concurrent active sessions simultaneously (one per device/platform). If a new session creation would breach this limit, the oldest active session is invalidated with reason 'concurrent_session_limit'.
CRUD Operations
Storage Configuration
Entity Relationships
A session may be associated with one or more token records (access + refresh pair)
A user can have multiple active sessions across different devices