Laravel Legacy Bridge: Carry Authenticated Sessions from a Legacy App into Laravel

Last updated on by

Laravel Legacy Bridge: Carry Authenticated Sessions from a Legacy App into Laravel image

Migrating an application to Laravel one route at a time leaves you with two apps and one user, and the user only logged into one of them. They sign in on the old CodeIgniter or custom PHP side, cross into a Laravel-handled route, and Laravel, knowing nothing about that session, sends them to a login form. Laravel Legacy Bridge, a package from Chris Keller, reads the legacy session cookie on unauthenticated requests, decodes the session payload out of the legacy database, and authenticates the matching user in Laravel.

Here's what the package covers:

  • A middleware bridge that runs only on unauthenticated requests and stops consulting the legacy store once Laravel has its own session
  • Payload decoding for native PHP session encoding, JSON, Laravel's base64(serialize()) format, and encrypted payloads
  • Resolver drivers to locate the user ID in the payload: auto-detection, an explicit dot-notation key, or a class of your own
  • Typed events for successful bridges, known failures, and unexpected exceptions, with no logging of its own
  • Legacy session invalidation so a given legacy session can only be bridged once
  • An interactive install command with framework presets, plus a verify command to test the wiring before real traffic hits it
  • Optional context carrying for values like a locale or cart ID that live in the legacy payload

How the Bridge Works

Registering one middleware puts the bridge in the request path:

->withMiddleware(function (Middleware $middleware) {
$middleware->web(append: [
\Chr15k\LegacyBridge\Http\Middleware\LegacySessionBridge::class,
]);
})

On an unauthenticated request it reads the legacy cookie (PHPSESSID by default), looks up the row in the legacy sessions table, decodes the payload, resolves a user ID, and calls loginUsingId(). Laravel then writes its own session, and later requests never touch the legacy store. The service provider also excludes the legacy cookie from Laravel's EncryptCookies middleware, so there's no encryptCookies() list to maintain.

Resolvers and Payload Formats

Every legacy app stores the user ID under a different key, so the lookup is configurable. Pick a resolver driver in config/legacy-bridge.php:

// Auto: tries known patterns (default)
'resolver' => ['driver' => 'auto'],
 
// Key: explicit dot-notation path
'resolver' => ['driver' => 'key', 'key' => 'user_id'],
 
// Custom: your own implementation
'resolver' => ['driver' => 'custom', 'class' => \App\Bridge\LegacyUserResolver::class],

The README recommends starting on auto and switching to key or custom before production. A custom resolver is also where you'd map old user IDs to new ones if your migration re-seeded the users table. Payload format is a separate setting (auto, php_session, json, laravel, or encrypted), and the encrypted format reads the legacy app's key from LEGACY_BRIDGE_APP_KEY.

Events

The bridge writes nothing to your log files. It dispatches LegacySessionBridged on success, LegacySessionBridgeFailed for known failures, and LegacySessionBridgeError for unexpected exceptions, and leaves the reporting to your listeners.

Failures carry a BridgeFailureReason enum with eight cases, among them MissingCookie, AmbiguousCookie, SessionExpired, PayloadDecodeFailed, and UserNotResolved. Some point at a misconfiguration, others are ordinary, like a session that timed out. The failure event also carries a BridgeContext DTO holding whatever the bridge resolved before it stopped:

$event->context->cookieName
$event->context->sessionId // resolved session ID (if reached)
$event->context->payload // decoded payload (if reached)
$event->context->userId // resolved user ID (if reached)
$event->context->requestContext // ['ip', 'path', 'method', 'user_agent']

Installation

composer require chr15k/laravel-legacy-bridge
php artisan legacy-bridge:install

The install command is interactive. It includes presets for common legacy frameworks, collects the database credentials, and writes the .env entries for you.

The Verify Command

A misconfigured bridge fails on real cookies against a real legacy database, which is not what your test suite exercises. The package ships a command that checks the configuration against that database:

php artisan legacy-bridge:verify
php artisan legacy-bridge:verify --session-id=a_real_session_id

Run it bare and it checks that the config is readable, the legacy database is reachable, the sessions table exists and has rows, the resolver is configured, and no cookie names collide. Pass a real session ID and it reports what the bridge would do with that session: format detected, payload keys found, user ID resolved, user confirmed to exist. It authenticates no one and modifies nothing.

Limitations and Security

The first release supports database sessions only, not the file, Redis, or Memcached drivers. It bridges web requests, not stateless API requests, and only into the default auth guard. It requires Laravel 13 and PHP 8.3 or newer.

Read the security section of the README before you deploy. The bridge deserializes payloads read straight from the legacy sessions table, which makes that database a trust boundary; the author recommends read-only credentials where possible. The legacy cookie travels unencrypted by design, the same way it did on the old app, so both applications need HTTPS. The default after_write invalidation strategy deletes the legacy session once Laravel writes its own, and the docs advise against setting it to never in production.

The source code and a full user guide covering framework presets, invalidation strategies, and troubleshooting are on GitHub.

Yannick Lyn Fatt photo

Staff Writer at Laravel News and Full stack web developer.

Cube

Laravel Newsletter

Join 40k+ other developers and never miss out on new tips, tutorials, and more.

image
SerpApi

The Web Search API for Your LLM and AI Applications

Visit SerpApi
Kirschbaum logo

Kirschbaum

Providing innovation and stability to ensure your web application succeeds.

Kirschbaum
Tinkerwell logo

Tinkerwell

The must-have code runner for Laravel developers. Tinker with AI, autocompletion and instant feedback on local and production environments.

Tinkerwell
PhpStorm logo

PhpStorm

The go-to PHP IDE with extensive out-of-the-box support for Laravel and its ecosystem.

PhpStorm
Acquaint Softtech logo

Acquaint Softtech

Acquaint Softtech offers AI-ready Laravel developers who onboard in 48 hours at $3000/Month with no lengthy sales process and a 100 percent money-back guarantee.

Acquaint Softtech
Laravel Cloud logo

Laravel Cloud

Easily create and manage your servers and deploy your Laravel applications in seconds.

Laravel Cloud
Harpoon: Next generation time tracking and invoicing logo

Harpoon: Next generation time tracking and invoicing

The next generation time-tracking and billing software that helps your agency plan and forecast a profitable future.

Harpoon: Next generation time tracking and invoicing
Shift logo

Shift

Running an old Laravel version? Instant, automated Laravel upgrades and code modernization to keep your applications fresh.

Shift
SaaSykit: Laravel SaaS Starter Kit logo

SaaSykit: Laravel SaaS Starter Kit

SaaSykit is a Multi-tenant Laravel SaaS Starter Kit that comes with all features required to run a modern SaaS. Payments, Beautiful Checkout, Admin Panel, User dashboard, Auth, Ready Components, Stats, Blog, Docs and more.

SaaSykit: Laravel SaaS Starter Kit
Lucky Media logo

Lucky Media

Get Lucky Now - the ideal choice for Laravel Development, with over a decade of experience!

Lucky Media
No Compromises logo

No Compromises

Joel and Aaron, the two seasoned devs from the No Compromises podcast, are now available to hire for your Laravel project. ⬧ Flat rate of $9500/mo. ⬧ No lengthy sales process. ⬧ No contracts. ⬧ 100% money back guarantee.

No Compromises

The latest

View all →
First-Party Image Processing in Laravel 13.20 image

First-Party Image Processing in Laravel 13.20

Read article
Laravel Quota: Usage Budgets for Calendar Periods image

Laravel Quota: Usage Budgets for Calendar Periods

Read article
Find the Security Vulnerabilities in Your Laravel App with Sensagraph image

Find the Security Vulnerabilities in Your Laravel App with Sensagraph

Read article
Uvora: A macOS Menu Bar App for Finding Laravel Projects image

Uvora: A macOS Menu Bar App for Finding Laravel Projects

Read article
Passwordless Sign-In with Fortify Two-Factor Support in Laravel image

Passwordless Sign-In with Fortify Two-Factor Support in Laravel

Read article
Intercept: Middleware Guardrails for Laravel AI Agents image

Intercept: Middleware Guardrails for Laravel AI Agents

Read article