Victor Walch Michnowicz

is a web application developer

Multi-site login July 7th, 2017

Assume we have three sites on three different domains all sharing the same codebase:

Even though all three sites share the same codebase, a login to one site only logs the user into that one site. This is because the session cookies are tied to each domain. In order to get one login to login a user to all sites we need to set the session cookie on all three sites at once. The solution: hidden images.

After a user logs into applesanonymous.at, for example, we add two hidden images to the page. These hidden images call a login script that runs some validations, sets a cookie, then outputs an invisible 1px by 1px image. The images look something like this:

<img src="https://betabuilders.biz/login?u=123&once=028dj&csrf=39fh4" width="1" height="1">
<img src="https://catcorner.cz/login?u=123&once=9dj3a&csrf=39fh4" width="1" height="1">

The required URL parameters are as follows:

Next we have a page to handle the requests to /login. In here we need to do the following:

  1. Ensure that the once code is valid and has not yet been used
  2. Ensure that the csrf token is valid
  3. Get the session hash for user u
  4. Set session hash cookie
  5. Invalidate one-time-use code
  6. Output image data

In this example the images are requested by applesanonymous.at and coming from betabuilders.biz and catcorner.cz. When the image loads the session hash cookie will be set on the requested image domains (betabuilders.biz and catcorner.cz) and thus logging in the user into that site.

Pseudocode

In pseudocode the image generation logic looks something like this:

echo '<img src="https://browniebuilders.biz?u=' + user.getId() + '&once=' + Once.generate() + '&csrf=' + user.session.getCsrfToken() + '" width="1" height="1">'
echo '<img src="https://catcorner.cz?u=' + user.getId() + '&once=' + Once.generate() + '&csrf=' + user.session.getCsrfToken() + '" width="1" height="1">'

And the /login logic looks something like this:

user = User.getById(request.u)

if ( !Once.isOnceValid(request.once) ) {
  exit
}

if ( user.session.isCsrfTokenValid(request.csrf) ) {
  exit
}

Once.invalidateOnce(request.once);

setCookie('session_hash', user.session.getHash())
setHeader('Content-type: image/gif')

echo imgData
exit

blog comments powered by Disqus