Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Stateless Session Laravel Package

overtrue/laravel-stateless-session

Stateless session driver for Laravel that keeps session data in signed cookies instead of server-side storage. No Redis, database, or files required, so sessions work across servers and scale horizontally. A drop-in driver that preserves the familiar session API while removing shared session state.

View on GitHub
Deep Wiki
Context7

Getting Started

This package gives Laravel API/SPA clients a cookie-less session: the client sends a session ID in a request header and Laravel returns the (possibly new) session ID in a response header. 3.0.0 is a maintenance-focused major: it drops Laravel ≤12 and PHP <8.3, fixes several header/session-ID edge cases, and adds real middleware test coverage.

Minimum steps:

  1. Upgrade the host app to Laravel 13 and PHP 8.3+ first — the package constraint will block installation otherwise.
  2. Read UPGRADE.md in the repo, then install:
    composer require overtrue/laravel-stateless-session:^3.0 --with-all-dependencies
    
  3. Publish/config the package config (header name, session driver expectations) and register the package middleware in Laravel 13's bootstrap/app.php middleware stack — the 3.0 docs now explicitly cover Laravel 13 registration.
  4. First use case: an Axios/fetch SPA or mobile app that already authenticates via Sanctum/tokens but wants Laravel session features (flash data, session()->regenerate(), validation error bags) without cookie handling.

Look first at the package's middleware and its config file to confirm the exact request/response header names in your install before wiring the client.

Implementation Patterns

Client-side header retention (the core pattern). Store the returned session ID and send it back on the next request. 3.0.0 now returns the header on the first request too, including when the incoming header is missing, empty, undefined, or 0, so the client rule is simply: always overwrite your stored ID with the most recent returned value.

axios.interceptors.response.use(
  (response) => {
    const id = response.headers['x-session-id']; // use your configured name
    if (id) store.set(id);
    return response;
  },
  (error) => {
    const id = error.response?.headers['x-session-id'];
    if (id) store.set(id);        // keep ID on 4xx/5xx, but don't swallow the error
    return Promise.reject(error);
  }
);

The response interceptor must reject, not resolve — the documented example deliberately retains IDs from rejected responses while re-throwing.

Keep the ID after regeneration. Login, logout and session()->invalidate() produce a new/final session ID; 3.0.0 returns the request's final session ID, so a single interceptor covers regeneration without extra round-trips or explicit "refresh session" endpoints.

CORS wiring. Because the ID lives in a custom header, browsers need explicit permission:

  • Access-Control-Expose-Headers: X-Session-Id so JS can read it;
  • the same header in Access-Control-Allow-Headers so it can be sent;
  • supports_credentials is not required for the header flow, but is if you mix in cookie auth.

Middleware placement. Register the package middleware on the same group as StartSession (typically the api group or a dedicated stateless group). It needs to run around session start/finish to read the incoming ID and write the outgoing one.

Testing pattern. Mirror the package's own approach: feature tests through the real HTTP kernel asserting the header on first request, on subsequent requests, after regenerate(), after invalidate(), and on error responses. Use Testbench for package-level tests and file/database session drivers so persistence is actually exercised.

Gotchas and Tips

  • No session means no header. 3.0.0 stopped exposing a session ID when no Laravel session is attached to the request. Client code must distinguish "header absent" (keep the old ID) from "header present" (overwrite) — do not write undefined/null into storage.
  • First-request change is behavioral. If you previously relied on "no header on the first request" to detect a fresh session, that signal is gone; use an explicit session flag or a /session bootstrap endpoint instead.
  • Cookie precedence is preserved. If both a cookie and the header are present, the cookie still wins. Mixed-mode apps (web guard + API guard on the same domain) can therefore appear to "ignore" the header — check whether a stale session cookie is being sent.
  • Custom header names are preserved, so renaming the configured header will silently break clients. Treat the header name as part of your public API contract and update CORS expose_headers/allow_headers in the same deploy.
  • Malformed IDs still go through Laravel's validation. A corrupted stored ID will be rejected/regenerated by the session guard rather than silently adopted; make sure your client recovers from a one-off 419/500 by retrying after storing the returned ID.
  • Error responses only help if the middleware ran. Exceptions thrown before session middleware (routing, global middleware, some 500s) won't carry the header — clients should tolerate intermittent missing headers.
  • Don't cache these responses. Session-ID headers are per-user; ensure CDN/reverse-proxy rules don't serve a cached response carrying someone else's ID (Cache-Control: no-store or Vary on the session header).
  • Debugging checklist: dump $response->headers in a feature test, confirm middleware ordering relative to StartSession, confirm CORS exposure, and confirm your client interceptor is attached to the same Axios instance as the failing call.
  • Composer hooks removed. 3.0.0 dropped broken install/update scripts referencing an undeclared cghooks binary; if you had worked around that failure in CI, the workaround can be deleted.
  • Version pinning. ^3.0 will float across patch/minor releases with more header-semantics fixes; pin exactly if your client contract is sensitive, and keep --with-all-dependencies for the Laravel 13 transitive upgrades.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager