Session
Data Entity
Description
Represents an authenticated user session, tracking the lifecycle of access and refresh tokens issued by the Authentication Module. Supports email/password, BankID, Vipps, biometric, and WebAuthn auth methods. Sessions are scoped per user and per device, enabling multi-device support, admin-initiated revocation, and forced expiry. The auth module owns only identity and session state — authorization logic lives in consuming products.
Data Structure
| Name | Type | Description | Constraints |
|---|---|---|---|
id |
uuid |
Primary key — unique session identifier issued at session creation | PKrequiredunique |
user_id |
uuid |
Foreign key to users. One user may have many concurrent sessions across devices and platforms. | required |
organization_id |
uuid |
Tenant scoping for per-organization signing material isolation. Global Admins have null organization_id since they have no default org context. | - |
auth_method |
enum |
Authentication method used to establish this session. Biometric sessions derive from an existing active session and do not create independent credential chains. | required |
access_token_hash |
string |
SHA-256 hash of the issued JWT access token. Never stored in plaintext. Used for token lookup and invalidation checks. | requiredunique |
refresh_token_hash |
string |
SHA-256 hash of the rotating refresh token. Rotated on every use — old hash is invalidated immediately on refresh. | requiredunique |
status |
enum |
Lifecycle state of the session. Revoked and expired sessions are retained for audit purposes and not deleted. | required |
revocation_reason |
enum |
Reason the session was terminated. Null for active sessions. | - |
revoked_by_user_id |
uuid |
User ID of the admin or system actor who revoked this session. Null if the session expired naturally or the user logged out themselves. | - |
client_type |
enum |
Which product client established this session. Determines token storage expectations: mobile uses secure platform store, admin portal uses HTTP-only cookies. | required |
device_fingerprint |
string |
Non-identifying device identifier derived from device attributes. Used for session grouping in the Session Management UI and detecting suspicious multi-device activity. | - |
device_name |
string |
Human-readable device label (e.g. 'iPhone 15', 'Chrome on macOS') shown in the Session Management UI so admins can identify sessions meaningfully. | - |
ip_address |
string |
IP address at session creation time. Stored for audit and security dashboard display. IPv4 or IPv6. | - |
user_agent |
string |
HTTP User-Agent header at session creation. Used for device type inference in the Session Management UI. | - |
access_token_expires_at |
datetime |
Expiry timestamp for the short-lived access token. Typically 15–60 minutes from issuance. Client must refresh before this time using the refresh token. | required |
refresh_token_expires_at |
datetime |
Expiry timestamp for the refresh token chain. When this passes the session is definitively over and the user must re-authenticate fully. | required |
last_activity_at |
datetime |
Timestamp of the most recent successful API call made with this session's access token. Used by the Session Management UI for inactivity display. | - |
revoked_at |
datetime |
Timestamp when the session was explicitly revoked. Null for active or naturally-expired sessions. | - |
module_context |
json |
Snapshot of the enabled module set for this user's organization at session creation time. Embedded in access tokens as a claims bag so clients can render navigation without an extra API call. | - |
created_at |
datetime |
Timestamp when the session was first established (initial sign-in). | required |
updated_at |
datetime |
Timestamp of the most recent session record mutation (status change, token rotation). | required |
Database Indexes
idx_sessions_user_id_status
Columns: user_id, status
idx_sessions_access_token_hash
Columns: access_token_hash
idx_sessions_refresh_token_hash
Columns: refresh_token_hash
idx_sessions_organization_id_status
Columns: organization_id, status
idx_sessions_refresh_token_expires_at
Columns: refresh_token_expires_at
idx_sessions_created_at
Columns: created_at
Validation Rules
access_token_hash_must_be_sha256
error
Validation failed
refresh_token_expires_after_access_token
error
Validation failed
status_transition_must_be_forward_only
error
Validation failed
revoked_session_requires_revocation_fields
error
Validation failed
organization_id_must_match_user_membership
error
Validation failed
ip_address_format_valid
warning
Validation failed
client_type_consistent_with_auth_method
error
Validation failed
Business Rules
refresh_token_rotation_on_use
Every time a refresh token is exchanged for a new access token, the old refresh_token_hash is immediately invalidated and a new one is issued. The session record is updated atomically. Reuse of a consumed refresh token triggers immediate session revocation and a security event.
refresh_token_reuse_terminates_session
If a previously consumed refresh_token_hash is presented again, the session is immediately revoked with reason 'refresh_token_reuse' and a security event is emitted. This defends against token theft scenarios where a stolen refresh token is used after the legitimate owner has already rotated it.
biometric_unlock_does_not_create_new_session
Biometric authentication (Face ID / fingerprint) unlocks access to an existing active session — it does not create a new credential chain. The auth_method is recorded as 'biometric_unlock' referencing the original session, which retains its own access_token_expires_at and refresh_token_expires_at.
global_admin_session_has_no_organization_context
Sessions created by Global Admins must have organization_id set to null. The auth module issues tokens with no org claims. Authorization for support access is time-bounded via organization_settings.support_access_until and is not embedded in the session record.
admin_revocation_logged_to_audit_trail
Any session revocation initiated by an org admin or global admin via the Session Management UI must produce an audit_logs entry for the organization whose user's session was revoked. Revoked_by_user_id and revocation_reason must both be set.
support_access_expiry_triggers_session_revocation
When a Global Admin's time-bounded support access expires (organization_settings.support_access_until passes), all active sessions for that global admin scoped to the org must be revoked immediately with reason 'support_access_expired'.
module_context_embedded_at_creation
At session creation the enabled module set for the user's organization is embedded in module_context and encoded into the access token claims bag. Clients read this on bootstrap to assemble navigation without an extra API call. The module context is refreshed on token rotation if the organization's module configuration has changed.
expired_sessions_retained_for_audit
Sessions are never hard-deleted on expiry. Expired sessions remain in the table with status='expired' to support the Audit Log and Security Dashboard. Archival (moving to cold storage) occurs after 1 year.