Attribute Exchange support for the OpenID component

The OpenID Attribute Exchange specification (or AX for short) has been around for quite a while, though I ignored it so far because at the time it was introduced (almost) no OpenID provider supported it. However, after Yahoo! announced they support Attribute Exchange, and someone recently mentioned it in a mail, it was time for me to have a look at it.
AX is in principle the “big brother” of the Simple Registration Extension (or SReg for short). Whereas SReg only allows you to retrieve nine commonly requested pieces of information, AX allows you to retrieve any identity information. And theoretically it also allows you to store/update your identity information at your OpenID provider. But it seems like no OpenID provider supports this feature…
Let’s have a look at an example.
First the login method:

// app/controllers/users_controller.php
class UsersController extends AppController {
public $components = array('Openid', 'RequestHandler');

public function login() {
$realm = 'http://'.$_SERVER['SERVER_NAME'];
$returnTo = $realm . '/users/login';

if ($this->RequestHandler->isPost()) {
$this->makeOpenIDRequest($this->data['User']['openid_identifier'], $returnTo, $realm);
} elseif ($this->Openid->isOpenIDResponse()) {
$this->handleOpenIDResponse($returnTo);
}
}
}

The next step is to implement the makeOpenIDRequest() method. For each attribute we want to retrieve, we have to create an Auth_OpenID_AX_AttrInfo object with the respective attribute type. A list of possible types is available on http://www.axschema.org/types/. Though there are many types defined, OpenID providers usually only support a small subset of those types.
The “1″ we pass to the make() method specifies the number of values we want for this type. In this example it doesn’t make much sense to specify a value other than “1″, but for other types it is theoretically possible to have multiple values (for example you could have defined multiple email addresses). It is an optional parameter and by default it is “1″.
The last parameter specifies whether the value of the attribute is required for our application. This is simply a hint for the OpenID provider so it could display this attribute differently, but it doesn’t guarantee a value is returned. By default this parameter is “false”.
(Update 2010-04-19: Google requires that you set the fourth parameter of the make() method: a string with an alias for the attribute.)

private function makeOpenIDRequest($openid, $returnTo, $realm) {
$attributes[] = Auth_OpenID_AX_AttrInfo::make('http://axschema.org/namePerson', 1, true);
$this->Openid->authenticate($openid, $returnTo, $realm, array('ax' => $attributes));
}

Finally, we have to implement the handleOpenIDResponse() method. As we expect only one value for the attribute we specified, we can use either get() or getSingle() to retrieve its value. getSingle() returns the value whereas get() returns an array.

private function handleOpenIDResponse($returnTo) {
$response = $this->Openid->getResponse($returnTo);

if ($response->status == Auth_OpenID_SUCCESS) {
$axResponse = Auth_OpenID_AX_FetchResponse::fromSuccessResponse($response);

if ($axResponse) {
debug($axResponse->get('http://axschema.org/namePerson'));
debug($axResponse->getSingle('http://axschema.org/namePerson'));
}
}
}

That’s it.
You can get the new version of the OpenID component from GitHub. If you use SReg in your code and you want to update to this version, please make sure to adapt your code in the following way:

// old
$this->Openid->authenticate($openid, $returnTo, $realm, array('email'), array('nickname'));

// new
$this->Openid->authenticate($openid, $returnTo, $realm, array('sreg_required' => array('email'), 'sreg_optional' => array('nickname')));

Feedback is welcome :)