aura/session-interface
aura/session-interface defines a clean PHP contract for session handling in Aura applications, specifying methods for session segments, flash messages, and CSRF token management so you can implement interchangeable session backends behind a consistent API.
aura/session-interface ships contracts only — no Session, no Segment, no Flash, no service provider, no config. It is the abstract half of Aura.Session: a handful of PSR-4 interfaces under Aura\Session\ (SessionInterface, SegmentInterface, FlashInterface, CsrfTokenInterface, and the segment factory contract). The concrete implementation lives in aura/session, a separate package. There are zero dependents and zero stars, so treat this as a contract you adopt deliberately, not a library you drop in and expect to work.
Minimal steps
composer require aura/session-interface
Then look at the source before writing anything:
ls vendor/aura/session-interface/src/
# SessionInterface.php SegmentInterface.php FlashInterface.php ...
Read the method signatures once, in full. The contract is small (under 20 methods per interface), and every one of them has a near-twin in Laravel with slightly different semantics.
First use case — and the only one that justifies the dependency: you are writing a package (audit log, wizard/checkout flow, multi-step onboarding, cart) that must run inside Laravel and inside a plain Aura/Slim/PHP app. You type-hint Aura\Session\SegmentInterface in your package and ship a Laravel adapter that delegates to Illuminate\Contracts\Session\Session. Nothing else about your day-to-day Laravel work changes.
If you are only ever going to run inside Laravel, do not install this. Use Illuminate\Session\Store directly; you gain nothing from an interface you immediately adapt away.
Adapter from Laravel's session to a segment. This is the core pattern. Implement the interface once, key everything under a namespace so you never collide with app session keys:
namespace App\Session;
use Aura\Session\SegmentInterface;
use Illuminate\Contracts\Session\Session;
final class LaravelSegment implements SegmentInterface
{
public function __construct(
private Session $session,
private string $name,
) {}
private function key(string $k): string
{
return "aura.{$this->name}.{$k}";
}
public function __get($key) { return $this->get($key); }
public function __set($key, $val) { $this->set($key, $val); }
public function __isset($key) { return $this->has($key); }
public function __unset($key) { $this->session->forget($this->key($key)); }
public function get($key, $d = null) { return $this->session->get($this->key($key), $d); }
public function set($key, $val) { $this->session->put($this->key($key), $val); }
public function has($key) { return $this->session->has($this->key($key)); }
public function clear()
{
foreach (array_keys($this->session->get($this->key(''), [])) as $k) {
$this->session->forget($this->key($k));
}
}
// ...remaining interface methods (flash, factory) — see gotchas below
}
Don't hand-write the method list. Let your IDE generate the stub from the interface (Implement methods in PhpStorm, generate-implementation elsewhere). Getting a single signature wrong is a fatal error, not a warning.
Bind it in a service provider, scoped per segment.
// App\Providers\SessionServiceProvider::register()
$this->app->bind(SegmentInterface::class, fn ($app) => new LaravelSegment(
$app['session.store'],
config('app.session_segment', 'app'),
));
If you need more than one segment, use contextual binding rather than inventing a locator:
$this->app->when(CheckoutWizard::class)
->needs(SegmentInterface::class)
->give(fn ($app) => new LaravelSegment($app['session.store'], 'checkout'));
Consume it like any other injected contract. Your package code has no idea Laravel exists:
final class CheckoutWizard
{
public function __construct(private SegmentInterface $segment) {}
public function advance(): void { $this->segment->set('step', 2); }
}
Testing. This is where the interface genuinely earns its keep. A 20-line array-backed fake replaces Session::start(), Session::put(), and the whole StartSession middleware stack in unit tests:
final class ArraySegment implements SegmentInterface { /* array $data */ }
$this->app->instance(SegmentInterface::class, new ArraySegment());
Map flash semantics explicitly. Aura separates "flash" (read-once) from "persistent" data via FlashInterface; Laravel conflates them into flash() / reflash() / pull(). Do the mapping inside the adapter — FlashInterface::get() should map to Session::pull(), not Session::get(). Document that in a comment, because it is the one place a reader will assume the wrong thing.
Cannot instantiate interface Aura\Session\SessionInterface, you (or a package) required the interface but not aura/session. Only install the implementation if you're actually outside Laravel.web middleware, StartSession, EncryptCookies, VerifyCsrfToken, and every session()-> call in the framework assume Illuminate\Contracts\Session\Session. The adapter pattern is the only viable integration.CsrfTokenInterface::isValid() exists, but Laravel's VerifyCsrfToken middleware already guards your routes. If your adapter's CSRF path runs and the middleware runs, you get confusing double-failures. If you're not using CSRF through the package, throw LogicException from that method rather than silently returning true.regenerateId() is a no-op you must document. Laravel already regenerates on login ($request->session()->regenerate()); calling it again inside an adapter is harmless but misleading. Prefer delegating to $session->regenerate() and noting who owns the lifecycle."aura/session-interface": "2.*") rather than floating — an interface change is a breaking change to your adapter and won't be caught by tests until runtime.composer require would register something, it won't. Everything is manual.app/. Use these types only in package/service-layer code. If Aura\Session\ appears in a controller, you've added abstraction with no second implementation to justify it.php artisan about for the driver, config/session.php for lifetime/domain, and dd(session()->all()) to see whether your adapter's aura.* namespace keys are actually landing. A clear() that forgets keys rather than flushing the store is usually the bug.How can I help you explore Laravel packages today?