Conceptual Outline for XRD-Based OpenID Discovery

This post is mostly me thinking out loud.

XRD is still very much a work-in-progress, and the OpenID community has yet to consider or endorse the new XRD protocol for its discovery needs. But since many of my readers consider OpenID discovery as the primary use case for XRD, I think this is a worthwhile excursion.

This post will offer one way in which XRD could be used as a new discovery layer for OpenID. Keep in mind that there are other ways XRD could be used for OpenID. The next post on this topic will look into specifying OpenID extensions as well as other ways to describe the provider.

But first, let’s cover the basics…

In this example, Joe (the end user) signs into a site using his OpenID URI: http://example.com/joe. The relaying party performs LRDD on the URI by trying one of these methods until successful:

  • Gets a representation of the URI using an HTTP GET request. If it’s a markup with <LINK> element support, looks for a ‘describedby’ relation:

<LINK href=”http://example.com/joe;xrd&#8221; rel=”describedby” type=”application/xrd+xml”>

  • Gets a representation of the URI using an HTTP HEAD or GET request and looks for a Link: HTTP response header with a ‘describedby’ relation:

Link: <http://example.com/joe;about&gt;; rel=”describedby”; type=”application/xrd+xml”

  • Gets the /host-meta document of the user’s OpenID domain (example.com), and look for a ‘describedby’ Link-Pattern:

Link-Pattern: <{uri};about”>; rel=”describedby“; type=”application/xrd+xml“

Each of these methods produces the same descriptor URI: http://example.com/joe;about. This URI points to an XRD document which describes the resource identified by the OpenID URI. It can contain many different attributes about the resource, but for the sake of simplicity, I will focus exclusively on OpenID.

Since the OpenID URI is used as an identifier for a person, we can consider the discovered XRD as the user’s descriptor. In OpenID, that URI can also identify a blog or a web page, and the other context can share the same descriptor which can describe its blog API as one example.

The user’s XRD looks like this:

<XRD>
<Subject>http://example.com/joe</Subject&gt;
<Type>http://openid.example.net/type/user</Type&gt;
<Link>
<Rel>http://openid.example.net/rel/provider</Rel&gt;
<URI>http://provider.example.org</URI&gt;
</Link>
</XRD>

What it means is that this XRD is talking about http://example.com/joe (the subject), which is described as an OpenID user identifier (using the made up http://openid.example.net/type/user type).

One way to think about this is that we are performing User-Discovery, learning more about the user. The question we are trying to answer here is ‘where is the user’s identity provider?‘, but in the future we may want to ask other questions such as ‘what is the user’s preferred language?‘.

The XRD lists a link to the OpenID identity provider (identified by the made up relation type http://openid.example.net/rel/provider). Note that the link does not say anything about this provider, only that it is the user’s provider. At this point, the relaying party knows where the provider is, but doesn’t know anything about it (such as what version of the protocol it supports).

The important point here is that this endpoint (http://provider.example.org) is not the OpenID authentication endpoint capable of “speaking” the OpenID protocol. This is an identifier for the provider as an entity (which may return an HTML page describing the service and offer people to sign up as one example).

The relaying part performs LRDD discovery on the provider’s URI to find out how to speak OpenID to it. Without repeating the three LRDD methods, the relaying party obtains the following XRD:

<XRD>
<Subject>http://provider.example.org</Subject&gt;
<Type>http://openid.example.net/type/provider</Type&gt;
<Link>
<Rel>http://openid.example.net/endpoint/auth/1.1</Rel&gt;
<URI>http://provider.example.org/1.1/signon</URI&gt;
</Link>
<Link>
<Rel>http://openid.example.net/endpoint/auth/2.0</Rel&gt;
<URI>http://provider.example.org/2.0/signon</URI&gt;
</Link>
</XRD>

This XRD is about the provider, and it tells the relaying party that this provider supports both version 1.1 and 2.0 of the OpenID protocol, and the endpoint of each. The main idea is that the provider controls which versions is supports and not the user. The user simply delegates its identity services to the provider, without trying to keep up with the different versions offered by the provider.

If the provider requires verifying the relaying party, it can perform discovery on the relaying party using the information provided in the authentication request (using the callback URI) and will receive an XRD like this:

<XRD>
<Subject>http://relayingparty.example.org</Subject&gt;
<Type>http://openid.example.net/type/relay</Type&gt;
<Link>
<Rel>http://openid.example.net/endpoint/callback</Rel&gt;
<URI>http://relayingparty.example.org/openid/callback</URI&gt;
</Link>
</XRD>

Which allows the provider to verify the callback URI included in the request. The provider can now authenticate the user and send him back to the relaying party successfully.