Skip to main content

User Sessions in Hanami

This document describes how user sessions work in Hanami, including configuration options for session limits, duration, and monitoring.

Overview​

Hanami manages user sessions with configurable limits and monitoring capabilities. Sessions are created when users authenticate and are automatically managed based on your configuration settings.

Session Configuration​

All session-related configurations are defined in the embedded application.yml file and can be overridden in either customer.yml or customer-env.yml — both are equally valid options.

Basic Configuration​

hanami:
session:
# Session timeout (default: 2 hours)
idle: PT2H

# Cookie configuration
cookie-http-only: true # Prevent JavaScript access to cookie
cookie-secure: true # Require HTTPS (set false for HTTP development)
cookie-same-site: strict # CSRF protection (strict, lax, or none)
cookie-name: JSESSIONID # Session cookie name
tracking-modes: COOKIE # Session tracking method

# Session limits
# Maximum total sessions across all users (-1 for unlimited, default: -1)
max-total-sessions: -1
# Maximum sessions per user (-1 for unlimited, default: -1)
max-sessions-per-user: -1
# Count multiple sessions from same user as 1 for total limit (default: false)
count-user-sessions-as-one: false
# Block new login when limit reached vs expire oldest session (default: false)
max-sessions-prevents-login: false

# Spring automatically inherits hanami.session values
server:
servlet:
session:
timeout: ${hanami.session.idle}
cookie:
max-age: ${hanami.session.idle}
http-only: ${hanami.session.cookie-http-only}
secure: ${hanami.session.cookie-secure}
same-site: ${hanami.session.cookie-same-site}
name: ${hanami.session.cookie-name}
tracking-modes: ${hanami.session.tracking-modes}

Session Duration​

Setting Session Timeout​

The session timeout determines how long a session remains active without user activity.

Format: ISO 8601 duration format

  • PT30M - 30 minutes
  • PT2H - 2 hours (default)
  • PT12H - 12 hours
  • PT24H - 24 hours
  • P7D - 7 days

Configuration:

hanami:
session:
idle: PT8H # Sessions expire after 8 hours of inactivity

Environment Variable: HANAMI_SESSION_IDLE

export HANAMI_SESSION_IDLE=PT12H

Hanami provides comprehensive cookie security settings to protect session cookies from various attacks.

HTTP-Only Flag​

Prevents JavaScript from accessing the session cookie, protecting against XSS attacks.

hanami:
session:
cookie-http-only: true # Recommended: true

Environment Variable: HANAMI_SESSION_COOKIE_HTTP_ONLY

Secure Flag​

Ensures cookies are only sent over HTTPS connections, protecting against man-in-the-middle attacks.

hanami:
session:
cookie-secure: true # Required for production, set false for HTTP development

Environment Variable: HANAMI_SESSION_COOKIE_SECURE

Important: Set to false only for local HTTP development. Always use true in production with HTTPS.

SameSite Attribute​

Protects against CSRF (Cross-Site Request Forgery) attacks.

Options:

  • strict (recommended) - Cookie sent only for same-site requests
  • lax - Cookie sent for same-site and top-level navigation
  • none - Cookie sent for all cross-site requests (requires cookie-secure: true)
hanami:
session:
cookie-same-site: strict # Recommended for maximum security

Environment Variable: HANAMI_SESSION_COOKIE_SAME_SITE

Customize the session cookie name (default: JSESSIONID).

hanami:
session:
cookie-name: HANAMI_SESSION

Environment Variable: HANAMI_SESSION_COOKIE_NAME

Tracking Modes​

Specifies how sessions are tracked (default: COOKIE).

hanami:
session:
tracking-modes: COOKIE

Environment Variable: HANAMI_SESSION_TRACKING_MODES

Options: COOKIE, URL, SSL (COOKIE is recommended)

Security Best Practices​

For production deployments with HTTPS:

hanami:
session:
cookie-http-only: true
cookie-secure: true
cookie-same-site: strict

For local HTTP development:

hanami:
session:
cookie-http-only: true
cookie-secure: false # HTTPS not available locally
cookie-same-site: lax

Session Limits​

Total Session Limits​

Controls the maximum number of active sessions across all users.

Options:

  • -1 (default) - Unlimited sessions
  • Any positive number - Custom limit (e.g., 100, 500)
hanami:
session:
max-total-sessions: 500 # Maximum 500 total sessions

Environment Variable: HANAMI_MAX_TOTAL_SESSIONS

export HANAMI_MAX_TOTAL_SESSIONS=500

Per-User Session Limits​

Controls how many concurrent sessions each user can have.

Options:

  • -1 (default) - Unlimited sessions per user
  • 1 - Single session per user (new login invalidates old session)
  • Any positive number - Custom limit per user
hanami:
session:
max-sessions-per-user: 3 # Each user can have up to 3 active sessions

Environment Variable: HANAMI_MAX_SESSIONS_PER_USER

export HANAMI_MAX_SESSIONS_PER_USER=3

Session Counting Modes​

Determines how multiple sessions from the same user count toward the total limit.

Options:

  • false (default) - Each session counts individually toward total limit
  • true - Multiple sessions from same user count as 1 toward total limit
hanami:
session:
count-user-sessions-as-one: true # User with 5 sessions counts as 1 toward total

Environment Variable: HANAMI_COUNT_USER_SESSIONS_AS_ONE

export HANAMI_COUNT_USER_SESSIONS_AS_ONE=true

Session Login Behavior​

Controls what happens when a user tries to login but has already reached their session limit.

Options:

  • false (default) - Allow new login, automatically expire oldest session
  • true - Block new login until user manually logs out from another session
hanami:
session:
max-sessions-prevents-login: true # Block login when limit reached

Environment Variable: HANAMI_MAX_SESSIONS_PREVENTS_LOGIN

export HANAMI_MAX_SESSIONS_PREVENTS_LOGIN=true

Behavior Examples:

When max-sessions-prevents-login: false (default):

  • User logs in on Device 1 ✅
  • User logs in on Device 2 → Device 1 session expires, Device 2 succeeds ✅
  • Better user experience (no login failures)

When max-sessions-prevents-login: true:

  • User logs in on Device 1 ✅
  • User tries to log in on Device 2 → Login is blocked ❌
  • User must manually logout from Device 1 first
  • More strict session control

Configuration Examples​

Unlimited Sessions (Default)​

hanami:
session:
idle: PT2H
max-total-sessions: -1
max-sessions-per-user: -1
count-user-sessions-as-one: false
  • No session limits
  • Users can have multiple concurrent sessions
  • Sessions expire after 2 hours of inactivity

Single Session Per User​

hanami:
session:
idle: PT24H
max-total-sessions: 100
max-sessions-per-user: 1
count-user-sessions-as-one: false
  • Each user can only have 1 session
  • Maximum 100 total sessions
  • New login invalidates previous session

Multiple Sessions Per User​

hanami:
session:
idle: PT8H
max-total-sessions: 500
max-sessions-per-user: 3
count-user-sessions-as-one: false
  • Each user can have up to 3 concurrent sessions
  • Maximum 500 total sessions across all users
  • Sessions expire after 8 hours of inactivity

Limit Unique Users Instead of Sessions​

hanami:
session:
idle: PT12H
max-total-sessions: 100
max-sessions-per-user: -1
count-user-sessions-as-one: true
  • Maximum 100 unique users can be logged in
  • Each user can have unlimited sessions
  • Multiple sessions from same user count as 1

Disabling Session Limits​

To completely disable session limits:

hanami:
session:
max-total-sessions: -1 # No total session limit
max-sessions-per-user: -1 # No per-user session limit

Session Monitoring​

Admin Interface​

Access session statistics through the admin interface:

  1. Navigate to /tools/admin
  2. Click on the "Session Management" tab
  3. View real-time session statistics including:
    • Active sessions count
    • Reader sessions count
    • Writer sessions count
    • Active users count
    • Reader Users count
    • Writer Users count
    • Effective count (based on counting mode)
    • Utilization percentage
    • Configuration details

Reader and Writer Sessions​

Hanami classifies user sessions as either "reader" (read-only permissions) or "writer" (full permissions) sessions. This classification helps administrators monitor different types of user access and can be used for capacity planning.

Session Classification​

Reader Sessions: Users with limited, read-only permissions Writer Sessions: Users with full permissions including write access

Authorization Modes​

Session classification works differently depending on your authorization mode:

Operations Mode (Role-based Authorization)​

  • All users are writers: In Operations mode, all sessions are classified as writer sessions
  • No reader classification: The isReader() method always returns false
  • Use case: When using role-based permissions where all authenticated users have similar capabilities

WAC Mode (WebAccessControl)​

  • SPARQL-based classification: Uses an external SPARQL query to determine reader status
  • Configurable logic: You can customize the reader detection logic
  • Dynamic classification: Reader/writer status is determined per session based on user's current group memberships

Configuring Reader Detection (WAC Mode Only)​

To configure reader/writer classification in WAC mode, create a SPARQL query file:

File: {ext-folder}/auth/is-reader.sparql.spel

# SPARQL ASK query to determine if a user is a reader
PREFIX acl: <http://www.w3.org/ns/auth/acl#>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX hanami: <https://hanami.app/ontology#>

ASK WHERE {
# User is a reader if they are member of the basic-users group
<https://hanami.app/auth/usergroup/basic-users> foaf:member <#{[userUri]}> .

# AND they have NO other group memberships
FILTER NOT EXISTS {
?otherGroup foaf:member <#{[userUri]}> .
FILTER (?otherGroup != <https://hanami.app/auth/usergroup/basic-users>)
}

# AND they are NOT an admin
FILTER NOT EXISTS {
<#{[userUri]}> hanami:isAdmin true .
}
}

Available Variables​

The query can use these template variables:

  • #{[userUri]} - The URI of the current user
  • #{[username]} - The username of the current user
  • #{[userGraph]} - The graph URI for the user

Query Logic Examples​

Basic Users Only (Default Example):

ASK WHERE {
# User is reader only if they ONLY belong to basic-users group
<https://hanami.app/auth/usergroup/basic-users> foaf:member <#{[userUri]}> .

# No other group memberships
FILTER NOT EXISTS {
?otherGroup foaf:member <#{[userUri]}> .
FILTER (?otherGroup != <https://hanami.app/auth/usergroup/basic-users>)
}
}

Specific Reader Role:

ASK WHERE {
# User has explicit reader role
<#{[userUri]}> hanami:hasRole "reader" .
}

Department-based Classification:

ASK WHERE {
# Users from specific departments are readers
<#{[userUri]}> hanami:department ?dept .
FILTER (?dept IN ("public-access", "external-users"))
}

Admin Override​

  • Admins are always writers: Users with isAdmin() = true are always classified as writers
  • Admin sessions bypass limits: Admins can have unlimited sessions regardless of configuration
  • Priority: Admin status takes precedence over reader query results

Default Behavior​

No Query File: If no is-reader.sparql.spel file exists, all users are classified as writers.

Query Error: If the query fails to execute, users default to writer status with a warning logged.

Monitoring Reader/Writer Sessions​

The admin interface shows separate counts for reader and writer sessions:

  1. Reader Sessions: Number of active sessions classified as readers
  2. Writer Sessions: Number of active sessions classified as writers
  3. Total: Reader sessions + Writer sessions = Active sessions

This information helps administrators:

  • Monitor different types of user access
  • Plan capacity for different user roles
  • Understand system usage patterns
  • Optimize session limits based on user types