core PK: id 7 required 2 unique

Description

A persisted JWT access or refresh token record associated with a user session. Tracks token value, expiry, issuer (email/password, BankID, Vipps), and revocation status. Used by the backend to validate mobile API requests and by the mobile client to maintain session continuity.

15
Attributes
7
Indexes
9
Validation Rules
18
CRUD Operations

Data Structure

Name Type Description Constraints
id uuid Unique identifier for the token record
PKrequiredunique
user_id uuid Foreign key reference to the owning user. A user may hold multiple active tokens across devices and token types.
required
session_id uuid Foreign key reference to the session that produced this token. Nullable because tokens may survive beyond a discrete session record or be issued prior to full session creation.
-
token_hash string SHA-256 hash of the raw JWT value. The raw token is never persisted; only the hash is stored for validation lookups. Backend compares hash of incoming Bearer token against this field.
requiredunique
token_type enum Distinguishes access tokens (short-lived, used in Authorization headers) from refresh tokens (long-lived, used to obtain new access tokens without re-authentication).
required
provider enum The authentication provider that issued the original authentication event which produced this token. Determines which identity verification path was used.
required
issued_at datetime Timestamp when the token was generated. Used for token age calculations and audit reporting.
required
expires_at datetime Timestamp after which the token is no longer valid. Access tokens: short-lived (15–60 minutes). Refresh tokens: long-lived (30 days). Backend rejects tokens where expires_at is in the past.
required
last_used_at datetime Timestamp of the most recent successful use of this token for an authenticated request. Updated on each valid API call. Used for idle session detection and security audit.
-
revoked_at datetime Timestamp when the token was explicitly revoked before natural expiry. Null means the token has not been revoked. Revoked tokens remain in the table for audit trail integrity.
-
revocation_reason enum Reason the token was revoked. Only populated when revoked_at is non-null.
-
token_family uuid Groups a refresh token with all access tokens it has produced. Used to detect refresh token reuse attacks: if a token from a consumed family is presented, all tokens in the family are immediately revoked.
-
device_id string Opaque device identifier provided by the mobile client. Allows per-device token management and targeted revocation (e.g., revoke all tokens for a lost device).
-
ip_address string IP address of the client at the time the token was issued. Stored for security audit and anomaly detection. Supports both IPv4 and IPv6 notation.
-
user_agent string HTTP User-Agent string from the client at token issuance time. Aids in identifying the device type and app version during security incident investigation.
-

Database Indexes

idx_auth_token_hash
btree unique

Columns: token_hash

idx_auth_token_user_id
btree

Columns: user_id

idx_auth_token_user_type
btree

Columns: user_id, token_type

idx_auth_token_session_id
btree

Columns: session_id

idx_auth_token_expires_at
btree

Columns: expires_at

idx_auth_token_token_family
btree

Columns: token_family

idx_auth_token_active
btree

Columns: user_id, revoked_at, expires_at

Validation Rules

token_hash_format error

Validation failed

token_hash_uniqueness error

Validation failed

expires_at_future error

Validation failed

user_id_exists error

Validation failed

revocation_reason_required_when_revoked error

Validation failed

revoked_at_immutable error

Validation failed

token_type_valid_enum error

Validation failed

provider_valid_enum error

Validation failed

ip_address_format warning

Validation failed

Business Rules

token_hash_only_storage
on_create

Raw JWT values must never be persisted to the database. Only the SHA-256 hex-encoded hash of the token is stored. The backend computes the hash of each incoming Bearer token and compares it against stored hashes.

access_token_short_expiry
on_create

Access tokens must expire within 60 minutes of issuance. This limits the window of exposure if an access token is intercepted or leaked.

refresh_token_long_expiry
on_create

Refresh tokens may have an expiry of up to 30 days. They must be stored in OS-level hardware-backed secure storage on the mobile device (Keychain/Keystore) and never in plain local storage.

revoked_tokens_retained
on_update

Revoked tokens must not be deleted immediately. They are retained with revoked_at and revocation_reason populated to preserve an immutable audit trail. Cleanup jobs may archive them after 1 year.

refresh_token_rotation
on_update

Each time a refresh token is used to obtain a new access token, the old refresh token must be revoked (reason: token_rotation) and a new refresh token issued in the same token_family. This enables reuse-attack detection.

token_family_reuse_revocation
always

If a refresh token that has already been consumed (revoked with reason token_rotation) is presented again, all tokens sharing the same token_family must be immediately revoked as a security_event. This indicates a stolen token is being replayed.

per_device_token_limit
on_create

A user should not accumulate unbounded active tokens. On login from a device that already has an active refresh token, the previous token for that device_id is revoked before issuing a new one.

provider_consistency
on_create

The provider field must match the authentication method used in the same session. A session initiated via BankID must not have tokens with provider='email_password'. Biometric tokens always inherit the provider of the initial full-authentication session.

cascade_revoke_on_account_deactivation
on_update

When a user account is deactivated by an admin, all active (non-expired, non-revoked) tokens for that user must be revoked with reason='account_deactivated'. This prevents deactivated users from continuing to make authenticated API requests.

jwt_claims_must_include_role_and_org
on_create

Every issued JWT must embed the user's current role and organization_id as claims. This enables stateless role-based access control validation in the auth middleware without requiring a database lookup on every request.

Storage Configuration

Storage Type
primary_table
Location
main_db
Partitioning
No Partitioning
Retention
archive_after_1year

Entity Relationships

session
incoming one_to_many

A session may be associated with one or more token records (access + refresh pair)

optional cascade delete
user
incoming one_to_many

A user can have multiple JWT tokens (access and refresh) active simultaneously across devices

required cascade delete