Single sign on across multiple subdomains

This had me stumped for a while so I figured it would be nice to share here to avoid others the grief.

The Requirement

The Yii application is divided into several subdomains, or each subdomain has its own Yii application.

A user should be able to log in to any subdomain and be logged in to another subdomain and the root domain.

The Solution

Actually rather simple through the use of cookies.

First thing is to set the user, session and cookie parameters properly in the main configuration file (only pertinent sections are shown) :

'components' => array(
	'user' => array(
		// enable cookie-based authentication
		'allowAutoLogin' => true,
	),
	// session configuration
	'session' => array(
		'savePath' => '/some/writeable/path',
		'cookieMode' => 'allow',
		'cookieParams' => array(
			'path' => '/',
			'domain' => '.yourdomain.com',
			'httpOnly' => true,
		),
	),

Explanation:

  • The 'savePath' should be set the same across all Yii applications that share the session.

  • Notice the '.' in front of the cookie domain name, this is what tells the cookie to span multiple subdomains, so 'yourdomain.com', 'a.yourdomain.com' and 'b.yourdoamin.com' will be matched.

  • The cookie's 'path' parameter is set to '/', this means the cookie will be valid for all paths.

Next, and this is the crucial bit with Yii (the above cookie configuration is generic PHP), the Yii application ID must be set in the config file:

array(
	'id' => 'yourdomain',

Explanation:

  • The Yii application ID is used to generate a unique signed key, used as a prefix to access user state information. The ID should be set manually so that it is identical for each Yii application that needs to share cookies and sessions.

Finally, the user cookie parameters must also be set to be identical as in the configuration file :

class MyWebUser extends CWebUser
{
	public $identityCookie = array(
		'path' => '/',
		'domain' => '.yourdomain.com',
	);
...

Or you can grab the settings from the configuration settings. This is especially useful when the settings will change, for example to set different domain names and/or paths for local, pre-production and production environments.

class MyWebUser extends CWebUser
{
	public function init()
	{
		$conf = Yii::app()->session->cookieParams;
		$this->identityCookie = array(
			'path' => $conf['path'],
			'domain' => $conf['domain'],
		);
		parent::init();
	}

That's it !!! This setup has been tested pretty thouroughly, but please provide comments/suggestions below on improving this article.