> ## Documentation Index
> Fetch the complete documentation index at: https://docs.strata.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Sessions

Sessions in the Maverics Orchestrator give every authenticated user a persistent, secure identity context -- their authentication state, tokens, and attributes travel with them across requests and applications without re-authenticating. Once a user logs in, the Orchestrator maintains their session server-side, making identity data available across many Orchestrator modes for as long as the session is valid. This page covers how sessions work, how to configure session lifetime and security, and how to set up store-agnostic features like dynamic expiration.

<Info>
  **Production support status:**

  * **Local sessions** -- Supported for production. Sessions are stored in-memory on each Orchestrator instance with LRU eviction. For single-node deployments, no additional configuration is needed. For multi-node deployments, configure sticky sessions (session affinity) on your load balancer. See [Local Sessions](/reference/orchestrator/sessions/local) for details.
  * **Cluster sessions** -- Experimental. Requires the `experimental.clusters` feature flag. Cluster sessions allow sessions to be shared across Orchestrator instances. When combined with cluster routing, this removes the need for load balancer affinity. Not yet supported for production workloads. This feature may be changed or removed without notice.
</Info>

<Note>
  **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.
</Note>

## How Sessions Work

The Orchestrator maintains server-side session state for each authenticated user. When a user authenticates, the Orchestrator creates a session containing their authentication state, tokens, and user attributes, then returns an opaque session cookie to the browser. On subsequent requests, the cookie identifies the session -- all sensitive data stays server-side, never in the cookie itself.

## Sessions and the Authentication Lifecycle

Sessions are created as part of the authentication flow and directly affect how users experience subsequent requests across all Orchestrator modes.

### When Sessions Are Created

A session is created after successful authentication in any Orchestrator mode. The Orchestrator stores the user's authentication state (which IdP authenticated them, when the authentication occurred), tokens received from upstream providers, and enriched attributes loaded from attribute providers. This all happens server-side -- only an opaque session cookie is sent to the client.

### How Sessions Affect Subsequent Requests

On subsequent requests, the Orchestrator checks for a valid session cookie. If a valid, non-expired session exists, the user is not redirected to the IdP again -- the Orchestrator uses the stored session data to fulfill the request (inject headers, issue tokens, serve LDAP entries). This is why session lifetime and idle timeout directly affect how often users must re-authenticate.

### Per-Mode Session Behavior

Each Orchestrator mode interacts with sessions differently:

* **HTTP Proxy** -- The session cookie is set on the proxy domain. Every proxied request checks the session. If the session is expired, the user is redirected to the IdP for re-authentication.
* **OIDC Provider** -- The session manages authorization server state. Token refresh can extend the effective session without requiring user interaction, as long as the session itself has not expired.
* **SAML Provider** -- The session manages IdP state. New SAML AuthnRequests check the existing session before redirecting to the upstream IdP. If a valid session exists, the Orchestrator can issue a SAML assertion without re-authenticating the user.
* **LDAP Provider** -- Sessions are per-connection bind state, not cookie-based. Each LDAP connection maintains its own authenticated context that lasts for the duration of the connection.
* **AI Identity Gateway** -- Sessions are token-based (OAuth), not cookie-based. Token expiry drives re-authentication rather than session cookie expiry.

### Session Expiration and Re-Authentication

When a session expires (either maximum lifetime reached or idle timeout exceeded), the next request triggers re-authentication. The user is redirected to the upstream IdP. If the IdP has its own active session (SSO), re-authentication may be transparent to the user -- they are redirected to the IdP and back without seeing a login prompt. If the IdP session has also expired, the user sees a login prompt.

For a complete overview of how authentication flows across all Orchestrator modes, see [How Authentication Works](/guides/authentication/how-auth-works).

## Session Security

Maverics sessions are designed for zero-trust environments:

* **256-bit session IDs** -- Generated using cryptographically secure random number generators (CSPRNG), providing 2<sup>256</sup> possible session IDs. Exceeds OWASP's minimum 64-bit entropy requirement with zero predictability between sessions.
* **Secure cookies by default** -- `HttpOnly` (no JavaScript access), `Secure` (HTTPS only), and `SameSite=None` (cross-site auth flows) are all enabled by default. These protect against session hijacking, XSS, and CSRF attacks.
* **Server-side storage** -- The session cookie is an opaque identifier only. User attributes, authentication state, and metadata are stored on the server, not in the cookie.
* **Automatic expiration** -- Sessions expire based on configurable maximum lifetime and idle timeout. Expired sessions are automatically purged from storage.

<Warning>
  Session cookies should be treated as secrets. If a malicious actor obtains a session cookie, they could impersonate the authenticated user for the duration of the session.
</Warning>

## Session Lifetime

Sessions support both maximum lifetime and idle timeout controls:

* **Maximum lifetime** -- The total time a session can exist after authentication, regardless of activity. Default: 12 hours.
* **Idle timeout** -- Time a session can remain inactive before expiring. Disabled by default.
* **Dynamic expiration** -- Service Extensions can evaluate session lifetime and idle timeout dynamically, enabling role-based or context-aware timeout policies (e.g., shorter timeouts for contractors, longer for employees).
* **Single logout** -- When a session expires or is explicitly terminated, all session data is deleted and the cookie is invalidated. Users must re-authenticate through the full authentication flow.

### Dynamic Session Expiration

Service Extensions allow dynamic, context-aware session expiration that applies to all session store types. Instead of static timeout values, you can evaluate session lifetime and idle timeout based on user attributes, roles, or request context.

```yaml maverics.yaml theme={null}
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.

```go session.go theme={null}
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))
}
```

<Note>
  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.
</Note>

#### 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`):

```yaml maverics.yaml theme={null}
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](/reference/orchestrator/service-extensions) 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

## Setup

<Tabs>
  <Tab title="Console UI">
    Session and cookie settings are configured per deployment under **Orchestrator Settings**.

    <Steps>
      <Step title="Open session settings">
        Navigate to **Deployments**, select a deployment, and click **Edit Session and Cookie** in the **Session and Cookie** section.
      </Step>

      <Step title="Configure session lifetime">
        Set **Max Lifetime Seconds** to control how long a session remains valid after authentication (default: 86400 seconds / 24 hours). Set **Idle Timeout** to expire sessions after a period of inactivity (0 disables idle timeout).
      </Step>

      <Step title="Configure capacity">
        Set **Cache Size** to limit the number of sessions stored in memory (default: 50,000). When this limit is reached, the oldest sessions are evicted.
      </Step>

      <Step title="Configure cookie settings">
        Under the **Cookie** heading, optionally set a **Domain** to scope the cookie to a parent domain (e.g., `.example.com`) and a **Name** to customize the session cookie name. Use the **Disable HttpOnly Attribute** and **Disable Secure Cookie Attribute** toggles only if your deployment specifically requires it -- both protections are enabled by default.
      </Step>

      <Step title="Optionally attach dynamic expiration Service Extensions">
        If you have Service Extensions uploaded, select them from the **Evaluate Session Maximum Lifetime Service Extension** and **Evaluate Session Idle Timeout Service Extension** dropdowns to enable dynamic, context-aware session expiration.
      </Step>

      <Step title="Save">
        Click **Save** to apply the settings.
      </Step>
    </Steps>

    <Note>
      The Console UI does not yet cover all session configuration options. Store type selection and duration-based lifetime values (e.g., `24h`, `15m`) are only available through configuration. See the **Configuration** tab for the full set of options.
    </Note>
  </Tab>

  <Tab title="Configuration">
    ```yaml maverics.yaml theme={null}
    session:
      store:
        type: local
        local:
          capacity: 50000
      lifetime:
        maxTimeout: 24h
        idleTimeout: 15m
      cookie:
        name: maverics_session
    ```

    When no session store is configured, the Orchestrator defaults to the local store with a capacity of 50,000 sessions.
  </Tab>
</Tabs>

## Configuration Reference

### Cookie Settings

| Key                              | Type    | Default              | Required | Description                                                                                                                                              |
| -------------------------------- | ------- | -------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `session.cookie.name`            | string  | `"maverics_session"` | No       | Session cookie name                                                                                                                                      |
| `session.cookie.domain`          | string  | --                   | No       | Cookie domain scope (defaults to the request host). Setting this to a parent domain (e.g., `.example.com`) exposes the session cookie to all subdomains. |
| `session.cookie.disableHTTPOnly` | boolean | `false`              | No       | Allow client-side script access to the session cookie                                                                                                    |
| `session.cookie.disableSecure`   | boolean | `false`              | No       | Allow the session cookie to be sent over unencrypted HTTP                                                                                                |

<Note>
  Cookie fields use **inverted booleans**: `disableHTTPOnly` and `disableSecure` rather than `httpOnly` and `secure`. The defaults keep both protections enabled. There is no `sameSite` field.
</Note>

### Session Lifetime

| Key                                  | Type   | Default | Required | Description                                                        |
| ------------------------------------ | ------ | ------- | -------- | ------------------------------------------------------------------ |
| `session.lifetime.maxTimeout`        | string | `"12h"` | No       | Maximum session duration (duration format, e.g., `"12h"`, `"30m"`) |
| `session.lifetime.idleTimeout`       | string | --      | No       | Idle timeout before session expires (duration format)              |
| `session.lifetime.evalIdleTimeoutSE` | object | --      | No       | Service Extension for dynamic idle timeout evaluation              |
| `session.lifetime.evalMaxLifetimeSE` | object | --      | No       | Service Extension for dynamic max lifetime evaluation              |

### Session Store

| Key                  | Type   | Default   | Required | Description                                                          |
| -------------------- | ------ | --------- | -------- | -------------------------------------------------------------------- |
| `session.store.type` | string | `"local"` | No       | Store type: `"local"` for single-node or `"cluster"` for distributed |

Store-specific fields are documented on each detail page: [Local Sessions](/reference/orchestrator/sessions/local#configuration-reference) and [Cluster Sessions](/reference/orchestrator/sessions/cluster#configuration-reference).

<Note>
  **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`
</Note>

## Store Types

| Type    | Description                   | Use Case                                                                                      |
| ------- | ----------------------------- | --------------------------------------------------------------------------------------------- |
| Local   | Single-node LRU session store | Production single-node and multi-node deployments with cookie-based sticky sessions (default) |
| Cluster | Distributed session store     | Multi-node deployments requiring shared sessions via Orchestrator clustering                  |

## Examples

<AccordionGroup>
  <Accordion title="Default session configuration">
    A standard session configuration with a local store, 24-hour maximum lifetime, and 15-minute idle timeout. This is appropriate for most production deployments where users should re-authenticate after a day or after 15 minutes of inactivity.

    ```yaml maverics.yaml theme={null}
    session:
      store:
        type: local
        local:
          capacity: 50000
      lifetime:
        maxTimeout: 24h
        idleTimeout: 15m
      cookie:
        name: maverics_session
    ```
  </Accordion>

  <Accordion title="Short-lived sessions for compliance">
    For environments subject to PCI DSS, HIPAA, or similar compliance frameworks that require aggressive session timeouts. This configuration enforces a 15-minute idle timeout and a 1-hour maximum lifetime, ensuring users re-authenticate frequently when accessing sensitive resources.

    ```yaml maverics.yaml theme={null}
    session:
      store:
        type: local
        local:
          capacity: 50000
      lifetime:
        maxTimeout: 1h
        idleTimeout: 15m
      cookie:
        name: maverics_session
    ```
  </Accordion>

  <Accordion title="Role-based dynamic expiration with Service Extensions">
    Use Service Extensions to apply different session timeouts based on user attributes. Contractors receive shorter sessions (5 minutes idle, 1 hour max) while full-time employees receive longer sessions (60 minutes idle, 12 hours max). See [Dynamic Session Expiration](#dynamic-session-expiration) above for the full Go code example.

    ```yaml maverics.yaml theme={null}
    session:
      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

    singleLogout:
      logoutURL: https://example.com/single-logout
      postLogout:
        redirectURL: https://example.com/index.html
    ```
  </Accordion>

  <Accordion title="Cross-subdomain session sharing">
    When users navigate between applications on different subdomains (e.g., `app.example.com` and `portal.example.com`), set the cookie domain to the parent domain so the session cookie is sent to all subdomains. This enables single sign-on across subdomains without requiring each application to initiate its own authentication flow.

    ```yaml maverics.yaml theme={null}
    session:
      store:
        type: local
        local:
          capacity: 50000
      lifetime:
        maxTimeout: 12h
        idleTimeout: 30m
      cookie:
        name: maverics_session
        domain: ".example.com"
    ```

    <Warning>
      Setting the cookie domain to a parent domain makes the session cookie accessible to **all** subdomains, including staging environments and third-party tools. If any subdomain is compromised, an attacker can hijack user sessions. Only use parent domain scoping when cross-subdomain sharing is explicitly required, and audit all subdomains to ensure they are trusted.
    </Warning>
  </Accordion>
</AccordionGroup>

## Session Detail Pages

<CardGroup cols={2}>
  <Card title="Local Sessions" icon="microchip" href="/reference/orchestrator/sessions/local">
    Production-ready single-node session storage with LRU eviction and sticky session guidance for multi-node
  </Card>

  <Card title="Cluster Sessions" icon="share-nodes" href="/reference/orchestrator/sessions/cluster">
    Experimental distributed session storage via Orchestrator clustering
  </Card>

  <Card title="Logout" icon="right-from-bracket" href="/reference/orchestrator/sessions/logout">
    Session layers, logout flows, and configuration for single logout, SAML, OIDC, and proxy logout
  </Card>
</CardGroup>

## Related Pages

<CardGroup cols={2}>
  <Card title="How Authentication Works" icon="key" href="/guides/authentication/how-auth-works">
    Complete overview of authentication flows across all Orchestrator modes
  </Card>

  <Card title="Authorization" icon="shield-check" href="/reference/orchestrator/authorization">
    Authorization rules and policy composition for access control
  </Card>

  <Card title="Caches" icon="database" href="/reference/orchestrator/caches">
    Key-value cache storage for Orchestrator modes and features
  </Card>

  <Card title="Scale for Production" icon="arrows-maximize" href="/guides/operations/scale">
    Configure multi-node deployments with sticky sessions and Redis caching
  </Card>
</CardGroup>
