Skip to main content
The local session store (session.store.type: local) is the production-recommended session store and the default when no store is configured. It provides single-node session storage with LRU (Least Recently Used) eviction. For multi-node deployments, configure sticky sessions (session affinity) on your load balancer so each user’s requests consistently reach the same Orchestrator instance. Configure cookie-based affinity using the Orchestrator’s session cookie (default: maverics_session, configurable via session.cookie.name) rather than IP-based affinity, which breaks when users share IPs or change networks.
Console terminology: In the Maverics Console, Orchestrator instances and configuration delivery are managed through Deployments. When working directly with YAML, configuration is managed as files delivered via the -config flag or MAVERICS_CONFIG environment variable.

Overview

When using the local session store, the Orchestrator stores session data in local process memory. Sessions are bounded by a configurable capacity limit and use LRU eviction when the capacity is reached. Session data is lost on restart and cannot be shared across multiple Orchestrator instances. In multi-node deployments with sticky sessions, if an Orchestrator node goes down, sessions on that node are lost. However, end users typically experience seamless continuity — the Orchestrator redirects the user to the upstream IdP, which recognizes the user’s existing IdP session and completes authentication silently without prompting for credentials. The Orchestrator then creates a new session transparently.

Use Cases

  • Production deployments — the recommended session store for single-node and multi-node (with sticky sessions) production deployments. No external infrastructure required. Configure your load balancer’s cookie-based affinity to use the maverics_session cookie.
  • Low-latency sessions — session access with zero network overhead since all data is in local memory
  • Development and testing — use local session storage during development without setting up external infrastructure

Configuration

Console UI documentation is coming soon. This section will walk you through configuring this component using the Maverics Console’s visual interface, including step-by-step screenshots and field descriptions.
Multi-node deployments: When configuring sticky sessions on your load balancer, use cookie-based affinity targeting the session cookie (maverics_session by default). Cookie-based affinity is more reliable than IP-based affinity because it works correctly when multiple users share the same IP address (e.g., behind a corporate NAT) or when a user’s IP changes mid-session (e.g., switching networks on a mobile device). If you have customized the cookie name via session.cookie.name, configure your load balancer to use that custom name instead.

Dynamic Session Expiration

Service Extensions allow dynamic, context-aware session expiration. Instead of static timeout values, you can evaluate session lifetime and idle timeout based on user attributes, roles, or request context.
maverics.yaml
session:
  cookie:
    domain: example.com
  lifetime:
    evalMaxLifetimeSE:
      funcName: EvalMaxLifetime
      file: /etc/maverics/extensions/session.go
    evalIdleTimeoutSE:
      funcName: EvalIdleTimeout
      file: /etc/maverics/extensions/session.go
  store:
    type: local
    local:
      capacity: 50000
Session expiration SE hooks have unique function signatures compared to other hooks. Instead of the standard (api, rw, req) signature, these hooks receive an additional time.Time parameter — createdAt for EvalMaxLifetime (when the session was created) and lastAccess for EvalIdleTimeout (when the session was last accessed). They also return a bool instead of returning nothing. These differences reflect the hooks’ role in session lifecycle evaluation rather than request processing.

Example: Role-Based Dynamic Expiration

In this example, contractors receive shorter sessions (5 minutes idle, 1 hour max) while full-time employees receive longer sessions (60 minutes idle, 12 hours max). When a session expires, the SE redirects the user to the single logout endpoint.
session.go
package main

import (
	"net/http"
	"time"

	"github.com/strata-io/service-extension/orchestrator"
)

const (
	sloEndpoint = "https://example.com/single-logout"

	contractorMaxLifetime = 1 * time.Hour
	contractorIdleTimeout = 5 * time.Minute

	fteMaxLifetime = 12 * time.Hour
	fteIdleTimeout = 60 * time.Minute
)

func EvalMaxLifetime(
	api orchestrator.Orchestrator,
	rw http.ResponseWriter,
	req *http.Request,
	createdAt time.Time,
) bool {
	log := api.Logger()

	employeeType, err := api.Session().GetString("okta.employeeType")
	if err != nil {
		log.Error("se", "failed to get employee type", "error", err.Error())
		return false
	}

	maxLifetime := fteMaxLifetime
	if employeeType == "contractor" {
		maxLifetime = contractorMaxLifetime
	}

	if sessionExpired(createdAt, maxLifetime) {
		log.Info("se", "max lifetime exceeded, redirecting to SLO",
			"employeeType", employeeType,
		)
		http.Redirect(rw, req, sloEndpoint, http.StatusFound)
		return false
	}

	return false
}

func EvalIdleTimeout(
	api orchestrator.Orchestrator,
	rw http.ResponseWriter,
	req *http.Request,
	lastAccess time.Time,
) bool {
	log := api.Logger()

	employeeType, err := api.Session().GetString("okta.employeeType")
	if err != nil {
		log.Error("se", "failed to get employee type", "error", err.Error())
		return false
	}

	idleTimeout := fteIdleTimeout
	if employeeType == "contractor" {
		idleTimeout = contractorIdleTimeout
	}

	if sessionExpired(lastAccess, idleTimeout) {
		log.Info("se", "idle timeout exceeded, redirecting to SLO",
			"employeeType", employeeType,
		)
		http.Redirect(rw, req, sloEndpoint, http.StatusFound)
		return false
	}

	return false
}

func sessionExpired(reference time.Time, timeout time.Duration) bool {
	return time.Now().After(reference.Add(timeout))
}
The bool return value controls whether the Orchestrator continues its default timeout evaluation. Returning true means the session is valid and the Orchestrator should continue processing normally. Returning false means the SE has handled the evaluation — either because the session expired and a redirect was issued, or because the SE has completed its check and is deferring to the Orchestrator’s default timeout behavior. In this example, both branches return false: the expired branch because a redirect was issued, and the non-expired branch because the SE has finished its evaluation.

Single Logout Configuration

The SE example above redirects expired sessions to the singleLogout endpoint. Configure singleLogout at the top level of the Orchestrator configuration (not nested under session):
maverics.yaml
singleLogout:
  logoutURL: https://example.com/single-logout
  postLogout:
    redirectURL: https://example.com/index.html
Set logoutURL to match the sloEndpoint constant in the Go code. After logout completes, the Orchestrator redirects the user to postLogout.redirectURL. You can also add a postLogoutSE Service Extension hook under postLogout to run custom logic after the logout flow completes. Use cases for dynamic expiration include:
  • Role-based timeouts — Contractors receive shorter sessions (e.g., 5 minutes idle, 1 hour max) while employees receive longer ones (e.g., 60 minutes idle, 12 hours max)
  • Risk-based session length — Reduce session lifetime when authentication originates from an unfamiliar device or location
  • Compliance enforcement — Force re-authentication for access to sensitive resources regardless of session state

Configuration Reference

KeyTypeDefaultRequiredDescription
session.cookie.namestring"maverics_session"NoSession cookie name
session.cookie.domainstringNoCookie domain scope (defaults to the request host). Setting this to a parent domain (e.g., .example.com) exposes the session cookie to all subdomains — see Troubleshooting for security guidance.
session.cookie.disableHTTPOnlybooleanfalseNoAllow client-side script access to the session cookie
session.cookie.disableSecurebooleanfalseNoAllow the session cookie to be sent over unencrypted HTTP
Cookie fields use inverted booleans: disableHTTPOnly and disableSecure rather than httpOnly and secure. The defaults keep both protections enabled. There is no sameSite field.

Session Lifetime

KeyTypeDefaultRequiredDescription
session.lifetime.maxTimeoutstring"12h"NoMaximum session duration (duration format, e.g., "12h", "30m")
session.lifetime.idleTimeoutstringNoIdle timeout before session expires (duration format)
session.lifetime.evalIdleTimeoutSEobjectNoService Extension for dynamic idle timeout evaluation
session.lifetime.evalMaxLifetimeSEobjectNoService Extension for dynamic max lifetime evaluation

Session Store (Local)

KeyTypeDefaultRequiredDescription
session.store.typestring"local"NoStore type: "local" for single-node or "cluster" for distributed
session.store.local.capacityinteger50000NoMaximum sessions for local store (LRU eviction when exceeded)
Deprecated fields — the following top-level session fields are still accepted but should be migrated to their new locations:
  • session.cacheSize — use session.store.local.capacity
  • session.maxLifetimeSeconds — use session.lifetime.maxTimeout
  • session.idleTimeout — use session.lifetime.idleTimeout
  • session.evalIdleTimeoutSE — use session.lifetime.evalIdleTimeoutSE
  • session.evalMaxLifetimeSE — use session.lifetime.evalMaxLifetimeSE

Example

Console UI documentation is coming soon. This section will walk you through configuring this component using the Maverics Console’s visual interface, including step-by-step screenshots and field descriptions.

Troubleshooting

  • Sessions lost on restart — the local session store does not persist sessions across Orchestrator restarts or node failures. This is expected behavior and applies even when using sticky sessions — sticky sessions route requests to the same node but do not persist session data. In practice, session loss is typically transparent to end users: when a user’s request reaches an Orchestrator without their session, the Orchestrator initiates a redirect to the upstream IdP, which recognizes the user’s existing IdP session and completes authentication silently (no login prompt). The Orchestrator then creates a new Maverics session. The user experiences a brief redirect but is not asked to log in again.
  • Sessions evicted unexpectedly — if the capacity limit is reached, the oldest sessions are evicted via LRU. Increase the capacity or shorten session lifetimes.
  • Sessions not shared across nodes — the local store is node-local. For production multi-node deployments, configure sticky sessions (session affinity) on your load balancer using cookie-based affinity on the maverics_session cookie (or your custom session.cookie.name value). For experimental shared sessions, see Cluster Sessions.
  • Cookie domain issues — if sessions are lost when navigating between subdomains, set session.cookie.domain to the parent domain (e.g., .example.com).
Setting session.cookie.domain to a parent domain (e.g., .example.com) makes the session cookie accessible to all subdomains under that domain, including staging environments, blogs, and any third-party tools hosted on subdomains. If any subdomain application is compromised, an attacker can read the session cookie and hijack user sessions. Scope the cookie domain as narrowly as possible — only set it to the parent domain if cross-subdomain session sharing is explicitly required. If parent domain scoping is necessary, audit all subdomains to ensure they are trusted.