ActiveManage Docs ← Back to activemanage.co.uk

Session Management

PHP Session Modes

How your users' sessions are stored has a direct impact on what your hosting can look like. A single web server can keep session files on its own disk and never think about it; the moment you put two web servers behind a load balancer, those file-based sessions stop working unless you switch to a shared store. ActiveManage supports four session modes and the right one for you depends entirely on your deployment shape.

The setting that drives this is PHP Session Mode under Site Settings → Session. You'll typically pick a mode once at install time and never touch it again, but if your infrastructure changes — for example you migrate from a single Apache box to an AWS Beanstalk auto-scaling group — you'll come back to revisit it.

files

The standard PHP session mode and the platform's default. Session data is written to files in a temporary folder on the web server itself (typically /tmp or the directory set in session.save_path). It needs zero additional infrastructure, runs everywhere PHP runs, and is the simplest mode to debug because you can literally cat a session file.

The downside is that sessions are pinned to one web server. If your hosting later puts a load balancer in front of multiple servers, a user who logs in on server A and is then routed to server B will look unauthenticated, because server B can't see server A's session files. Some load balancers can be configured for sticky sessions to work around this, but it's a fragile arrangement.

Use files mode when: you're running a single web server, you're in development, or you're confident you'll never need to scale out horizontally.

redis

Sessions are stored in a Redis database — an in-memory key-value store known for very low-latency reads and writes. Redis is the de-facto choice for load-balanced PHP deployments because every web server reads sessions from the same Redis instance, so requests can be served by any server and find the right session.

You'll need a Redis server reachable from each web server. Common patterns: a dedicated EC2 instance running Redis, an AWS ElastiCache for Redis cluster, or a managed Redis service like Redis Cloud or Upstash. Configure the hostname and port via the Session Server Hostname and Session Server Port Site Settings.

Use Redis mode when: you're running multiple web servers behind a load balancer, you want fast session reads, and you have (or can spin up) a Redis instance.

memcached

Sessions are stored in a Memcached system. Functionally similar to Redis — multi-server-friendly, fast — but with a simpler feature set (no native persistence, simpler data types). The choice between Redis and Memcached usually comes down to whatever's already running in your infrastructure rather than any meaningful capability difference for session storage specifically.

Like Redis, you'll point ActiveManage at a Memcached host via the same Session Server Hostname and Session Server Port settings. AWS ElastiCache supports both, so on AWS the decision often comes down to whether you also need Redis's broader feature set for other parts of your stack.

dynamodb

Sessions are stored in an AWS DynamoDB table. This is the right pick for serverless or auto-scaling deployments — DynamoDB is fully managed, scales automatically, and doesn't require you to size and maintain a Redis or Memcached instance.

Configure the endpoint via $AM_awsDDBendpoint and the table name via $AM_awsDDBsessionTBL in your config. The AWS credentials configured for S3 and SNS are reused. DynamoDB read/write costs are typically negligible for session traffic — each request is a single small read and (occasionally) a small write.

Use DynamoDB mode when: you're deploying to AWS and want zero session-server management, or you're running in a serverless environment where keeping a long-running Redis/Memcached process around is awkward.

Choosing the right mode for your deployment

To summarise the typical decision matrix:

  • Single server, internal tools, dev/staging: files.
  • Load-balanced production on your own infrastructure: Redis (or Memcached if it's already there).
  • AWS production with autoscaling: DynamoDB, or Redis via ElastiCache.
  • Serverless (Lambda-based deployments): DynamoDB.

Screenshot of the Session section of Site Settings showing the PHP Session Mode dropdown with the four mode options and the conditional Session Server Hostname and Port fields beneath it

Note: Changing modes mid-flight will log out every currently-authenticated user because their existing session data lives in the old store. Plan a maintenance window for any mode change in production.

Always Check Session

By default, ActiveManage trusts the session cookie that arrives with each request. If the cookie matches a known session ID and the session hasn't expired, the user is treated as authenticated. That's fast — there's no extra database lookup per request — but it has a downside: if you revoke a session in the admin panel (say, because you suspect a hijack), the user with the stolen cookie can keep using it until the session naturally expires.

The Always Check Session setting changes that. When on, every request hits the session store (Redis, Memcached, DynamoDB, or the session-files directory) and verifies the session is still considered valid. Revocations take effect immediately. The trade-off is one extra round-trip per request — usually a millisecond or two against Redis on the same network, more against DynamoDB or files.

What "checking" actually does

With Always Check Session enabled, every page load (and every AJAX request) the platform serves runs three additional pieces of logic before the user is considered authenticated:

  1. Look up the session by ID in the configured session store.
  2. Confirm the session hasn't been marked as revoked, expired, or invalidated by an admin action.
  3. If two related settings are also on (covered in their own articles), verify the IP address and User Agent haven't changed since login.

If any of those steps fail, the user is silently logged out and redirected to the login page. Their previous request isn't fulfilled — they have to log back in to continue.

When to enable

There are three concrete situations where the cost of the extra lookup is worth paying. The first is any environment with strict regulatory requirements — healthcare, banking, payments — where stale sessions are unacceptable. The second is when you've built a "log out everywhere" feature in your application; without Always Check Session, that feature can't actually log users out until their sessions naturally expire. The third is when session hijacking is a concrete concern, typically because your app handles particularly sensitive data and you want every layer of defence available.

When to leave it off

For high-throughput consumer apps where session theft isn't a primary threat and the marginal latency matters, leave it off. The default "trust the cookie" model is what most PHP applications use and it's been good enough for the vast majority of the web for two decades. A B2C content site, a marketing portal, or a low-stakes self-service tool doesn't need the extra cost.

Performance budget

To put numbers on it: against a same-region Redis or Memcached, the extra lookup is around 0.5–2ms per request. Against DynamoDB it's typically 5–15ms. Against files-on-disk (rare for large deployments) it's whatever the disk I/O latency is, which can range from sub-millisecond on SSDs to many milliseconds on overloaded shared hosting.

Screenshot of the Session section of Site Settings highlighting the Always Check Session toggle and the dependent options (Verify IP, Verify User Agent) that only apply when this is enabled

Tip: If you enable Always Check Session, you'll typically also want to think about Maximum Session Idle Time (separate setting). Together they give you: "any revocation takes effect immediately" and "sessions auto-expire after N minutes of inactivity".

Verifying IP and User Agent

If an attacker manages to steal a user's session cookie — by intercepting traffic, exploiting an XSS bug, or pinching it off an unattended device — they can typically use it from anywhere, on any browser. ActiveManage offers two additional checks that make stolen-cookie attacks much harder, at the cost of some inconvenience for legitimate users whose connection or browser legitimately changes mid-session.

Both settings sit under Site Settings → Session and both only take effect when Always Check Session is also on — without that, the platform doesn't look up the session per request and so can't run the comparison.

Verify User's IP Address

When this is on, the platform stamps the user's IP into their session at login. Every subsequent request compares the incoming IP to the stamped one. If they don't match — typically because the user moved between networks — the session is invalidated and the user is forced to log back in.

For desktop users sitting at a single workstation all day, this is invisible. For mobile users it's a constant nuisance: walking from the office Wi-Fi to the lift's 4G connection counts as an IP change, as does the morning commute moving between cell towers. Most modern apps avoid IP-pinning for this reason.

There's a third group it's actively wrong for: users behind carrier-grade NATs (often the case in mobile networks) where the apparent IP can rotate every few minutes without the user moving at all. In those environments, IP-pinning effectively logs the user out constantly.

The platform's own documentation captures the right summary: this option isn't recommended for mobile users that switch between mobile and Wi-Fi connections. Enable it for hardened admin-only environments; leave it off for anything customer-facing.

Verify User's Browser User Agent

This compares the visitor's browser User-Agent header against the User-Agent stamped at login time. A mismatch — almost always because the browser auto-updated mid-session — logs the user out.

It's less intrusive than IP-pinning because most browsers' User-Agent strings stay stable for hours or days at a time. It catches the easiest form of cookie theft, where an attacker grabs the cookie and pastes it into a different browser entirely.

The catch: anti-tracking browsers like Brave and Safari sometimes randomise User-Agent components for privacy. And every Chrome auto-update flips the version number, which counts as a change. Test in your user population before turning it on.

Combined effect

With both on, an attacker who steals a session cookie would need to spoof both the original IP and the original User-Agent to use it. That's hard. The legitimate-user cost is real though — IP changes from network roaming, plus User-Agent changes from browser updates, mean users see unexpected re-login prompts every few days.

Recommended configurations

Three sensible profiles, depending on your threat model:

  • Maximum security (internal admin tools): Always Check Session + Verify IP + Verify User Agent + short Idle Time (15 min). Locks down hard at the cost of UX.
  • Balanced (typical business apps): Always Check Session + Verify User Agent only. Catches obvious cookie theft without disrupting mobile users.
  • Convenience-first (consumer apps, marketing portals): Always Check Session off; rely on session expiry and HTTPS for cookie protection.

Screenshot of the Session section of Site Settings showing the Verify User's IP Address and Verify User's Browser User Agent toggles, with help text underneath each

Warning: If you're considering enabling IP verification for an app with any mobile usage, run it past your support team first. They'll be the ones answering "why did I get logged out again?" tickets.

Setting Maximum Session Idle Time

Every session has an idle timer that resets on activity. When the user goes idle for longer than the configured maximum, their session is invalidated and they're forced to log back in. That's the primary defence against unattended-device risk — someone walking away from their desk, closing the lid of their laptop without locking it, leaving a session live in a browser tab forever.

The setting lives at Site Settings → Session → Maximum Session Idle Time, and it's expressed in seconds. The default in the shipped configuration is 1,209,600 seconds — exactly two weeks. That's deliberately generous: it's a value that suits consumer apps where convenience trumps strict security. For business apps, you'll typically want to bring it down significantly.

What counts as activity

Any HTTP request that includes the session cookie resets the idle timer. That includes:

  • A page navigation (clicking a link, submitting a form).
  • Any AJAX call the page makes — saving a row, loading a dropdown, fetching a notification count.
  • A polling request from the platform's real-time poller (if Polling is enabled).
  • Any browser background tab that's open and periodically pinging the server.

That last point is important: a user with the platform open in any background tab will not appear idle even if they're nowhere near the screen. Apps that include client-side polling effectively never auto-log-out their users while the tab is open. If you need stricter behaviour, combine the idle time with a separate "hard timeout" via custom JS that logs the user out after N minutes of no mouse/keyboard activity.

Picking a value for your app

Three concrete recommendations based on different app types:

  • Banking, healthcare, payment processing — 900 seconds (15 minutes). Conventional in regulated industries. Some standards (PCI-DSS in particular) mandate timeouts in this range.
  • Internal business apps — 14,400 seconds (4 hours). Long enough that a typical working session doesn't get interrupted, short enough that a desk left for a long meeting will require re-authentication.
  • Consumer apps — 1,209,600 seconds (2 weeks). Conventional for B2C — users get frustrated if they have to log in again every visit.

You can also segment by surface. If your platform has both an admin panel and a customer portal, consider a tighter idle time for admin sessions and a looser one for portal sessions. That's typically configured via custom code (the underlying setting is global) but it's worth implementing for any app where admins handle sensitive data.

Coordinating with Always Check Session

The idle timeout is enforced regardless of Always Check Session. When that setting is off, the timeout is checked at request time using the session cookie's age; when it's on, the timeout is checked against the session's last-activity timestamp in the configured store. The effective behaviour is the same — only the implementation differs.

What the user sees when they time out

Their next request after the timeout returns to the login page rather than completing. If they were in the middle of filling in a long form, they'll typically lose their unsaved input. To avoid that frustration for users with high-value forms (UIVs, complex Custom Forms), consider implementing client-side draft-save logic that persists in-progress form data to localStorage on every change.

Screenshot of the Session section of Site Settings showing the Maximum Session Idle Time field, with the value entered in seconds and the help text explaining the timing

Tip: Test your chosen idle time with a real user workflow before going live. A 15-minute timeout that interrupts the typical user's day every few hours quickly becomes a major source of support tickets and lost work.
Note: Both Always Check Session and IP/User-Agent verification operate independently of the idle time. You can have a long idle time but short revocation latency, or a short idle time but no per-request session lookups — they're orthogonal levers.