PHPackages                             seba1rx/sessionadmin - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Authentication &amp; Authorization](/categories/authentication)
4. /
5. seba1rx/sessionadmin

ActiveLibrary[Authentication &amp; Authorization](/categories/authentication)

seba1rx/sessionadmin
====================

PHP session management with security hardening, hijacking detection, and URL authorization for MPA and SPA applications

v3.0.0(2mo ago)2741MITPHPPHP &gt;=8.1

Since Jan 26Pushed 2mo ago1 watchersCompare

[ Source](https://github.com/seba1rx/SessionAdmin)[ Packagist](https://packagist.org/packages/seba1rx/sessionadmin)[ RSS](/packages/seba1rx-sessionadmin/feed)WikiDiscussions main Synced today

READMEChangelog (10)Dependencies (5)Versions (13)Used By (1)

seba1rx/sessionadmin
====================

[](#seba1rxsessionadmin)

PHP session management library with security hardening and URL authorization.

```
composer require seba1rx/sessionadmin
```

---

Features
--------

[](#features)

**Session security**

- Named sessions with configurable cookie parameters
- Hijacking detection: IP prefix + User-Agent fingerprint verified on every request
- Proxy-aware IP detection (reads `X-Forwarded-For` and equivalent headers)
- Session destruction when a request arrives after the configured lifetime
- Session ID regenerated on login and randomly (~3% of requests) to resist fixation

**URL authorization (MPA)**

- Define an `$allowedUrls` list; guests are redirected to `index.php` on any unlisted page
- Expandable per user role or profile
- Disable entirely for SPA apps (`$appIsSpa = true`, the default)

---

Quick start
-----------

[](#quick-start)

`SessionAdmin` is abstract with no abstract methods. Extend it and define a constructor:

```
// App/MySession.php
namespace App;

use Seba1rx\SessionAdmin\SessionAdmin;

class MySession extends SessionAdmin
{
    public function __construct()
    {
        $this->sessionName     = 'my_app';
        $this->sessionLifetime = 3600;          // seconds
        $this->keys            = ['theme' => 'light']; // pre-seeded session keys
    }
}
```

Then on every entry point, before any output:

```
require 'vendor/autoload.php';

$session = new App\MySession();
$session->useAuthorization  = false; // true for MPA URL enforcement
$session->activateSession();         // replaces session_start()

// On login:
$session->createUserSession($userId);

// On logout:
$session->terminate();

// Auth check:
if (!empty($_SESSION['sessionadmin']['isUser'])) {
    // authenticated
}
```

### Public API

[](#public-api)

MethodDescription`activateSession()`Starts or resumes the session; runs all security checks`createUserSession(mixed $id)`Marks session as authenticated, regenerates session ID`terminate()`Destroys session, reinitialises as guest, redirects to `index.php` (MPA)`setSessionHandler(\SessionHandlerInterface $handler)`Plug in a custom storage backend; call before `activateSession()``setTabHandler(TabHandlerInterface $handler)`Inject a tab handler (e.g. `seba1rx/tabmanager`); call before `activateSession()`The full class is documented via docblocks — your IDE will surface every property and its purpose.

### Session data written to `$_SESSION['sessionadmin']`

[](#session-data-written-to-_sessionsessionadmin)

KeyPresentDescription`appType`Always`'SPA'` or `'MPA'` — reflects the `$appIsSpa` flag`isUser`Always`true` when authenticated, `false` for guests`id_user`After loginValue passed to `createUserSession()``msg`AlwaysHuman-readable state label`uniqueId`Always12-char hex token, stable for the session lifetime`ipPrefix`AlwaysFirst N octets of the client IP (hijacking detection)`userAgent`AlwaysUser-Agent string (hijacking detection)`time_atRequest`AlwaysUnix timestamp of the last request`time_sinceLastRequest`AlwaysSeconds elapsed since the previous request`allowedUrl`**MPA only**Copy of `$allowedUrls` used for URL authorization`urlIsAllowedToLoad`**MPA only**`true` when the current URL is in the allow-list`allowedUrl` and `urlIsAllowedToLoad` are omitted entirely in SPA mode — they only make sense when URL authorization is active.

---

Custom session storage
----------------------

[](#custom-session-storage)

By default the package uses PHP's native file-based session storage. Pass any [`SessionHandlerInterface`](https://www.php.net/manual/en/class.sessionhandlerinterface.php) implementation to `setSessionHandler()` before calling `activateSession()` to swap the backend:

```
$session = new App\MySession();
$session->setSessionHandler(new RedisSessionHandler($redis));
$session->activateSession();
```

Any PSR-compatible or custom handler works — Redis, database, encrypted file store, etc. The handler must be set **before** `activateSession()` because PHP applies the handler prior to calling `session_start()`.

---

Tab isolation (optional)
------------------------

[](#tab-isolation-optional)

Per-browser-tab session isolation is provided by the companion package [`seba1rx/tabmanager`](https://github.com/seba1rx/tabmanager), which implements `TabHandlerInterface`.

```
composer require seba1rx/tabmanager
```

Inject it before calling `activateSession()` using `SessionAdminBridge` — the integration class shipped with tabmanager:

```
use Seba1rx\TabManager\Bridge\SessionAdminBridge;

$session = new App\MySession();
$session->setTabHandler(new SessionAdminBridge());
$session->autoCleanupTabs = 30; // optional: remove tabs inactive for > 30 s
$session->activateSession();

// After the JS client has registered the tab:
$session->tabHandler->set('cart', ['apple' => 3]);
$cart  = $session->tabHandler->get('cart');
$ready = $session->tabHandler->isTabIndexed(); // false until JS registers the tab
```

`SessionAdminBridge` extends `TabManager` but does not call `session_start()` in its constructor — `activateSession()` owns the session lifecycle and configures the session name and cookie parameters before the session starts. Both packages write to distinct keys in `$_SESSION` (`sessionadmin` vs `tabmanager`) and do not interfere with each other.

#### Tab session loss (`autoCleanupTabs` + `tabmanager:session-lost`)

[](#tab-session-loss-autocleanuptabs--tabmanagersession-lost)

When `$autoCleanupTabs` is set, SessionAdmin prunes inactive tabs on every `activateSession()` call. If the browser suspends a tab (Chrome Memory Saver, OS memory pressure), the JS heartbeat pauses — and the tab may be pruned while invisible. When the user returns, tabmanager's JS client checks `/tabmanager/tab-status`. If the tab is no longer indexed, it fires a `tabmanager:session-lost` event on `document` and stops the heartbeat. Listen for this event to show a warning or prompt the user to reload:

```
document.addEventListener('tabmanager:session-lost', () => {
    // Tab data was pruned by autoCleanupTabs while the tab was suspended.
    // Show a warning and let the user decide whether to reload.
    showSessionLostBanner();
});
```

The event carries `event.detail.tabId` with the UUID of the lost tab.

---

Contracts (interfaces)
----------------------

[](#contracts-interfaces)

The package ships two interfaces under `Seba1rx\SessionAdmin\Contracts`:

InterfaceRoleKey methods`SessionInterface`Implemented by `SessionAdmin``activateSession()`, `createUserSession()`, `terminate()``TabHandlerInterface`Implemented by `seba1rx/tabmanager``set()`, `get()`, `isTabIndexed()`, `cleanupInactiveTabs()`, …`TabHandlerInterface` defines the full tab lifecycle contract. Any class implementing it can be injected via `setTabHandler()` — SessionAdmin never depends on the concrete `TabManager` class.

**Example — mock session in tests:**

```
$mockSession = $this->createMock(SessionInterface::class);
$mockSession->expects($this->once())->method('activateSession');
```

**Example — mock tab handler in tests:**

```
$mockTabs = $this->createMock(TabHandlerInterface::class);
$mockTabs->method('get')->with('cart')->willReturn(['apple' => 3]);
$session->setTabHandler($mockTabs);
```

---

Demos
-----

[](#demos)

DemoDescription[`demo/basic/`](demo/basic/)Minimal login/logout — the simplest possible implementation[`demo/mpa/`](demo/mpa/)Multi-page app with URL authorization and `$allowedUrls`[`demo/spa/`](demo/spa/)Single-page app, SPA mode, AJAX login[`demo/tabmanager/`](demo/tabmanager/)SessionAdmin + TabManager integration — shared session, per-tab data isolationEach demo is self-contained with its own `composer.json`.

### Running a demo locally

[](#running-a-demo-locally)

1. Install dependencies for the chosen demo:

```
cd demo/basic
composer install
```

2. Start PHP's built-in web server from the demo directory:

```
php -S localhost:8000
```

3. Open your browser and navigate to:

```
http://localhost:8000

```

> The built-in server serves `index.php` by default. Change the port if `8000` is already in use (`php -S localhost:8080`).

###  Health Score

45

—

FairBetter than 91% of packages

Maintenance87

Actively maintained with recent releases

Popularity13

Limited adoption so far

Community11

Small or concentrated contributor base

Maturity58

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~86 days

Recently: every ~9 days

Total

11

Last Release

64d ago

Major Versions

1.2.2 → 2.0.02025-10-14

v2.2 → v3.0.02026-06-14

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/15786046?v=4)[seba1rx](/maintainers/seba1rx)[@seba1rx](https://github.com/seba1rx)

---

Top Contributors

[![seba1rx](https://avatars.githubusercontent.com/u/15786046?v=4)](https://github.com/seba1rx "seba1rx (90 commits)")

---

Tags

phpsecurityAuthenticationsessionSPAmpaHijacking

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/seba1rx-sessionadmin/health.svg)

```
[![Health](https://phpackages.com/badges/seba1rx-sessionadmin/health.svg)](https://phpackages.com/packages/seba1rx-sessionadmin)
```

###  Alternatives

[alajusticia/laravel-logins

Session management in Laravel apps, user notifications on new access, support for multiple separate remember tokens, IP geolocation, User-Agent parser

2115.6k](/packages/alajusticia-laravel-logins)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
