Single Sign-on across Sub-Domains in Drupal with No Extra Modules

With the multitude of single sign-on modules out there for Drupal, it's easy to miss the fact that Drupal has a built-in single sign on mechanism already. No modules, no configuration, just 20 easy lines of PHP in your site's settings.php file. This solution works for a lot of clients, but the set of requirements is pretty specific as to when you can use this approach. This includes:

  • The sites sharing a single log-in must be on the same domain. For example:
    • www.example.com
    • forums.example.com
    • subsite.example.com
  • You must be using MySQL.
  • Your sites must be on the same hardware cluster to be able to query each other's databases.

If your site fits within those requirements, you're on your way to simple, efficient, and easy Single Sign-on!

The concept for this single sign-on approach is based around Drupal's ability to prefix database tables. As you may know, you can run multiple Drupal sites on the same MySQL database. However, most sites are not configured this way, each site is given it's own dedicated database. Drupal's table prefixing can be combined with MySQL's ability to query across databases to make a simple "shared table" across multiple sites. Then you just need to set a cookie domain so that the two sites share session information and you're done!

If that sounds a little heady, let's just look at the code. Open the settings.php file (usually located in sites/default/settings.php) for your two sites. These sites can be in entirely different Drupal installs, or they can be under the same Drupal installation if you're using multisite capabilities.

Master Site Configuration

In your "Master" site (the one that the user information will be stored in), you don't need to make hardly any changes. There should be a line similar to this in your settings.php file:

  
$db_url = 'mysql://user:pass@localhost/master_database';
$db_prefix = '';
  

You don't need to change this at all. The master site stores all the user names, passwords, and sessions. However there is another line further down in settings.php that let's you specify a cookie domain. This needs to be un-commented (remove the leading # sign) and set to the name of your domain. Make sure you include the leading period before the domain.

  
$cookie_domain = '.example.com';
  

Slave Site Configuration

The slave site will connect to the Master site's database for certain tables, specifically the ones that include user information. This makes it so that user's simply "log in" using the information from the master site's database.

Here's where we use MySQL's database name prefixing, where all queries to the "slave" database are simply prefixed with the name of the slave database. Same goes for the master.

  
$db_url = 'mysql://user:pass@localhost/slave_database';
$db_prefix = array(
   'default'   => 'name_of_slave_database.',
   'users'     => 'name_of_master_database.',
   'sessions'  => 'name_of_master_database.',
   'role'      => 'name_of_master_database.',
   'authmap'   => 'name_of_master_database.',
);
  

Then we configure the site to use the same "shared" cookie domain as the master.

  
$cookie_domain = '.example.com';
  

The method for a user logging in does not change, the user can just use the exact same user name and password on both sites, logging into one will immediately log you into all of them. Users can even change their passwords and have it work across sites, and you can still use Views to build listings of users without any changes at all. Hurray for shared cookies.

Taking it further

Just by adding a few lines of code to your settings.php file on your different sites can make shared login a piece of cake. Note that this makes it so that other user-related information may need to also be shared. Specifically if you're using Profile module, you may also want to share the "profile_fields" and the "profile_values" tables.

One caveat you might encounter is that your user picture URLs are all relative to the Master site's files directory. To solve this problem, you can create a symlink from "files/pictures" on your slave sites to point to the master site's "files/pictures" directory.

  
ln -s /usr/home/example.com/sites/default/files/pictures /usr/home/subsite.example.com/sites/default/files/pictures
  

Again, this approach will only work across subdomains of the same domain and if the sites are hosted on the same set of servers. The security built into browsers prevents domains from reading the cookies of completely different domains, which is when you'll need to look into other solutions such as OpenID Provider, Single Sign-on, or Bakery.

This article was sponsored by our friends at Dooce! You can see this in action between their shared sites:

  • http://www.dooce.com
  • http://community.dooce.com

Get in touch with us

Tell us about your project or drop us a line. We'd love to hear from you!