Shared Laravel sessions across domains

Yusuf
4 min readMay 7, 2021

--

Let’s see how easily sessions can be shared across different domains in Laravel. This is ideal for SaaS apps where tenants can bring in their own domains, as in medium.com or hashnode.com. The full code is here.

Introduction

First things first, keep in mind that what is meant by shared sessions, is that for a given visitor, all the domains will share a single session. This implies that if you’re on domain john.x and you Session::put(‘x’, ‘y’), you’ll be able to Session::get(‘x’) on alice.y.

Let me also tell you that you won’t need any migration, require traits, or anything silly. Your app will stay your app. And I think that the code is pretty much valid for any Laravel version.

The technique discussed here can be used for:

  • Centralized authentication: a user is connected everywhere once logged in, and disconnected everywhere once his session is destroyed (logged out or session expired). Basically, Auth::user() is consistent across domains. That may sound similar to SSO, OAuth, JWT, and others, but it’s a piece of cake to implement and we’re not talking about sharing only users here, but sessions.
  • Global carts: you’re running something like Shopify or BigCartel, but you want the customer to keep his products in his cart as he jumps from shop to shop, or restaurant to restaurant? Keep reading!
  • Analytics: better tracking by considering Jane as Jane on different domains.
  • Many others: the only limit is your imagination.

Sharing across subdomains is not in the scope of this article as that’s merely changing the SESSION_DOMAIN parameter. The simple trick I’ll show in a minute is a generic one, and works with any domain running on a single Laravel application. Sharing across different applications will be briefly evoked later.

So, what’s the magic?

Simple: for a given visitor, keep the session identifier Session:getId(), which is hidden in the session cookie, consistent across domains/apps. Normally, Laravel would create a session for each domain and for each visitor, since browsers don’t allow sharing cookies across domains.

There are two key concepts we should stick to:

  • A single domain should be responsible of creating sessions. We’ll call it the portal domain. It can simply be your main/central domain.
  • Other domains, called tenant domains, should use the sessions created in that portal domain. Although we’re talking about tenants here, these domains might be completely different websites which need common sessions.

There may be several ways of implementing this. I’ll be glad to hear your ideas. You may continue reading to see my implementation.

The flow

You won’t feel the redirection, believe me

The code

Note that I am storing sessions in the database, and the implementation below makes use of the DatabaseSessionHandler, but you can easily adapt it to any other session handler. Check out the doc to setup database sessions. The goal it to prevent tenant domains from creating sessions, and let them retrieve sessions from the portal domain.

.env
config\app.php
app\Providers\SessionServiceProvider.php
app\Extensions\DatabaseSessionHandler.php
app\Http\Kernel.php
app\Http\Middleware\StartSession.php
routes\web.php

Security concerns

As you may have noticed from the lazy implementation, we are passing the encrypted session ID in the URL when redirecting back from the portal to the tenant domain. Laravel internally uses the same encryption mechanism for hiding the session ID in the session cookie, but passing sensible data in URLs can possibly cause security issues depending on your requirements as explained here and here. You may tweak my implementation as you wish to meet your demands. For instance, instead of passing (encrypted) session IDs, passing single use and short living tokens which tenants will use to retrieve the sessions might be a good starting point.

Conclusion

We saw how to share sessions between domains inside a single Laravel application. It is also possible to have the portal as an application, and let other distinct applications make use of it, but your applications will need to read the sessions from the same place (e.g. common database).

If you know that a user will not require a session, in the case of a crawler for example, you may skip the whole process so that no redirection occur. As for a regular user, he will be redirected only once till his session/cookie expires. Depending on your configuration, it may be a single redirection until the user exits his browser, as it may be single redirection for a complete year.

You may also check how Hashnode implemented a similar idea here using Cloudflare Workers (they redirect on every single page unfortunately), don’t forget to open the Network tab of your browser to check the redirections.

Medium and Hashnode both use the redirection technique described here

Note that in case you need to store domain specific data, you can always do it with cookies, or use a parallel session pool.

Lastly, as a bonus, you may use the following JS code in order to get rid of that ugly query session parameter:

That’s all folks. And remember, the World is a shared session.

--

--

Yusuf
Yusuf

Written by Yusuf

Software Engineer. Working with Java/Spring and PHP/Laravel. Building APIs and SaaSes. Occasionally playing with matrices.

No responses yet