Monday, March 30, 2009

How to pretty much guarantee that you might get an email address with OpenID

OpenID itself is just an authentication protocol.  It takes OpenID extensions to get more information about the user like their name or email address.  In fact there are two popular extensions that can provide this kind of information: Simple Registration (sreg) and Attribute Exchange (AX).  A web site that wants to accept OpenID logins (this site is called a relying party, or “RP”) and also gather the user’s email address at the same time may do so, but unfortunately it is quite complicated to get the best user experience.

OpenID Providers (aka “OP”) can support either or both of these extensions.  And while the sreg extension is straightforward and consistently implemented, AX is divided.  Let me explain.  If you want an email of a user and you’re using the sreg extension, just ask for the value for “email”.  Simple.  But if you’re using AX, you have to ask for these three attributes:

  1. http://axschema.org/contact/email
  2. http://schema.openid.net/contact/email
  3. http://openid.net/schema/contact/email

Why on earth?  Well, AX is extensible, so any attribute URI can be used to refer to some value that you want.  Unfortunately, before AX was a finalized spec several popular OPs picked up support for it and made up different ways of describing the simple user’s email attribute.  The very unfortunate thing is that once AX standardized on one Type URI form for the common attributes (#1 on my list above), many of these OPs didn’t bother to update their code to support the official attribute type URI.

What that means for RPs that can request authentication against arbitrary OPs is that they have to request all three of these attributes and then check for any of these three attributes to have values in the AX response.  But that’s not all, of course…

Some OPs don’t support AX at all, so you also have to send an sreg extension request to fetch the email address, and an RP then has a total of four places in the response to check for an email address.  Why not just use the unified sreg, you ask?  Because Google doesn’t support sreg – only AX. 

Oh, and Google will only give you an email address if the RP indicates that it is an AX “required” attribute.  Google completely ignores attribute requests marked as “requested”.

And Yahoo! doesn’t support either sreg or AX extensions at all.  They plan to, but as yet they don’t give out any user information to RPs. 

So if you request email addresses via sreg and AX, and for AX you ask for the email in all three forms, and if you mark them as required, you have a pretty good chance of maybe getting a user’s email address.

OpenID is really cool.  But retrieving attributes about a user is not.  AX is a great spec, but very, very poorly adopted.

9 comments:

  1. Thanks for the info - I was having trouble getting any attributes from Google, because I didn't think to make them required (not requested).

    It seems the request / require protocol is also broken because even though I make other attributes required (e.g. country), the login still succeeds, but country is not returned. This makes the distinction between request and require meaningless!

    Loving DotNetOpenAuth, have implemented OpenId logins on a site I'm doing in a day! :)

    ReplyDelete
  2. Very helpful post indeed. In the whole vague mess of openid felt like fresh air. Thank you very much!

    ReplyDelete
  3. A code snippet for checking all the four types will really enhance the post.. Actually I am stucked in a similar kind of problem and finding a solution since last two days... Have a look at http://stackoverflow.com/questions/7228733/openid-attribute-exchange-is-not-working-spring-security

    ReplyDelete
  4. thanks for the info.However, am able to fetch email,firstname,lastname,country,language details.But I was struggling from past few days to fetch gender,dob,address (city),phone nos etc from user profile.I am using google as my OP and my api is openid4java.
    I have read many posts,forums, source code of AuthRequest,AuthSuccess,FetchRequest,FetchResponse etc...but had no clue and i am still not clear if these values cannot be fetched for sure...If yes...any other alternative please...some help is much appreciated

    ReplyDelete
  5. @jyothy, the data you're asking for isn't offered by Google, or almost any other OpenID Provider.

    ReplyDelete
  6. Hi Andrew,

    Following is my code written in vb.net.

    Protected Sub OpenIdButton3_LoggedIn(ByVal sender As Object, ByVal e As DotNetOpenAuth.OpenId.RelyingParty.OpenIdEventArgs) Handles OpenIdButton3.LoggedIn

    OpenIdButton3.Visible = False
    Dim profile As ClaimsResponse = e.Response.GetExtension(Of ClaimsResponse)()
    Dim email As String = profile.Email
    MsgBox(email)
    End Sub

    But Line

    Dim email As String = profile.Email

    is giving a following error.

    Exception Details: System.NullReferenceException: Object reference not set to an instance of an object.

    Can u help me on this?

    Regards

    ReplyDelete
  7. Sikandar, you're missing a null check on your 'profile' local variable before retrieving its email address. It will be null when the Provider doesn't include the extension in its response.

    ReplyDelete
  8. hi Andrew

    I know that but I wanted email address to be returned by the provider. Finally, got it to worked. thx a lot.

    ReplyDelete
  9. Hi Andrew so if Google and yahoo are not providing data through OpenId then what authentication would be used to access user information.

    ReplyDelete