Attention: We are retiring the ASP.NET Community Blogs. Learn more >

Fetching User Details from OpenId via Attribute Exchange

CropperCapture[4]Rob Conery did another excellent episode of his MVC Storefront series the other day where he ripped out his user membership code and replaced it with OpenId.

Implementing the whole OpenId protocol yourself isn't necessary as there are some great libraries for you out there which makes it really, really simple to use and integrate with both WebFoms and A SP.NET MVC. Rob uses the DotNetOpenId library to authenticate the user but didn't show how to fetch user details like the user full name.

Well, this is possible using Attribute Exchange which is a way of transferring information about the user between the OpenID provider and relying party. The DotNetOpenId library supports this too, and it just requires a small change to the DotNetOpenId code samples I've seen out there.

First, most people redirect to the provider like this:

openid.CreateRequest(id).RedirectToProvider();

But instead, create the request manually and add extension requests to fetch user information (like the name for example) to it before redirecting:

var openidRequest = openid.CreateRequest(id);
var fetch = new FetchRequest();
fetch.AddAttribute(new AttributeRequest("http://schema.openid.net/namePerson"));
openidRequest.AddExtension(fetch);

openidRequest.RedirectToProvider();

Just keep on adding the attributes you're interested in, like email, website etc. Remeber to inform your user about you wanting to fetch the extra information before doing the authentication.

After a successful OpenId authentication the provider redirects back to your site and you normally authenticate and redirect like this:

switch (openid.Response.Status)
{
    case AuthenticationStatus.Authenticated:
        FormsAuthentication.RedirectFromLoginPage(openid.Response.ClaimedIdentifier, false);
//...snip...

Now, before the redirect statement, you have the chance to fetch out the attributes you asked for from the OpenId response, like this for example:

switch (openid.Response.Status)
{
    case AuthenticationStatus.Authenticated:
        var fetch = openid.Response.GetExtension<FetchResponse>();
        if (fetch != null)
        {
            //assuming we got data back from the provider - add sanity check to this :)
            var name = fetch.GetAttribute("http://schema.openid.net/namePerson").Values[0];
            //...store name in session or something...
}
FormsAuthentication.RedirectFromLoginPage(openid.Response.ClaimedIdentifier, false); //...snip...

Note that DotNetOpenId library offers a few "well known" attributes as enums which all uses the "axschema.org" schema, but they do not work with the myOpenId provider. That's why I'm using the "schema.openid.net" schema instead.

Rakuto Furutani blogged about the attribute schema problems in a Ruby on Rails post:

myOpenID supports only some attributes that can be exchange with OpenID Attribute Exchange, but you should care about Type URI, because myOpenID doesn't support Type URI described on "http://www.axschema.org/types/". You should specify Type URI with "http://schema.openid.net/" instead.

It could be I'm using an older version of the DotNetOpenId library and it's been changed in newed releases. I have to check this out.

Also, Andrew Arnott has written a longer post on how to use DotNetOpenId's Attribute Extensions extension which you should read if you want some more in-depth sample code (he's using ASP.NET WebForms).

No Comments