OpenID

OpenID Exchange 1.0

Note: This specification is now largely abandoned. The original author feels that this use-case would be better served by a simpler protocol specified in terms of OAuth. This page is left for historical interest.

Contents

Abstract

OpenID Exchange is a protocol for user-accompanied data exchange between endpoints. It is a transport upon which other services can be built.

Terminology

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in[RFC2119].

Definitions and Conventions

User:
(AKA "End User" or "Subject".) A person with a digital identity who participates in OpenID based identity information exchanges using their client software, typically a web browser.
Transaction:
A complete iteration of the exchange protocol specified herein.
Consumer:
The party that initiates the transaction.
Endpoint:
The party that responds to the request.
Permission URL:
The URL at which the Endpoint does interactive permission checking.
Dependent Service:
A separate specification that makes use of this protocol for data exchange.

Overview

The protocol described herein is for exchange of data between two parties that is accompanied and authorized by a user. The data that is exchanged is outside of the scope of this protocol and can be defined by services that use this protocol as a transport. This protocol itself uses HTTP as a transport.

Expected applications of this protocol include, but are not limited to, exchange of user information as part of OpenID authentication, and in a more general sense permitting a site to access a user's private information stored on another site with authorization from the user. Other, more esoteric applications are possible such as using Exchange as a transport for the SOAP message-passing protocol.

The exchange protocol itself does not have a service type URI, since it acts only as a transport for other services. Services making use of this protocol will, if they are to use OpenID service discovery, define their own service type URIs and specify the use of this protocol in their respective specifications.

This protocol is based around the familiar HTTP request-response paradigm, with the consumer initiating a request and the endpoint responding with some answer. The request-response process is augmented with additional steps for user authentication and authorization. The contents of the request and response messages is defined by the dependent service.

Exchange uses HTTP authentication facilities for its signalling in order to allow HTTP proxy servers that are unaware of OpenID Exchange to properly process (specifically, to avoid caching) Exchange requests, but the specific implementation and UI requirements for this protocol mean that it is not useful as a general-purpose HTTP authentication mechanism.

This protocol is not necessarily used in conjunction with an OpenID Authentication request, but a mechanism is provided to conduct both Authentication and Exchange in parallel if allowed by the dependent service and if the endpoint is also an OpenID Provider as described in[OpenID.authentication-2.0].

Protocol Flow

The protocol flow can be summarized as follows:

  1. Consumer makes a direct request to Endpoint URL to set up the request.
  2. Endpoint responds with a transaction handle.
  3. Consumer redirects the user's browser to the endpoint URL, including the transaction handle as a query string argument.
  4. Endpoint authenticates the user and requests the user's permission to carry out the transaction.
  5. Endpoint redirects the user's browser back to the consumer indicating that the request is successful.
  6. Consumer makes a direct request to Endpoint URL to retrieve the response.

The request and response are passed directly between the consumer and endpoint. Only the user authorization step is performed through the user's browser.

The mechanism for discovering the Endpoint URL for a particular service is outside the scope of this specification and will be defined within each dependent service specification.

Non-human Users

This protocol does not include any specific support for non-human users or non-browser user-agents. The browser-oriented phase of each transaction involves an arbitrary permission request that will often be via HTML forms, so non-human agents will need support added for each endpoint on a case-by-case basis. While this limitation is acknowledged, this specification is aimed at authorization by human users and addressing this limitation is left for a later specification.

Exchange Protocol

Fundamentals

There are two mechanisms used for message passing in this protocol.

Direct HTTP Requests

The Exchange protocol uses HTTP as a transport for direct requests, optionally encapsulated inside SSL or TLS. The protocol signalling is performed via the HTTP Authentication mechanisms, with protocol-specific data encoded in a custom HTTP header field.

An request includes an Authorization header and an X-OIDex header as follows:

   Authorization: OIDExchange
   X-OIDex: key1="value1", key2="value2", key3="value3"

Some servers/frameworks do not allow applications access to the Authorization header. For these frameworks, it is permissible for the endpoint to assume the presence of a correct Authorization header if an X-OIDex header is present. However, Consumers MUST include the correct Authorization header, and endpoints which are able to do so SHOULD ensure its presense and fail the request if it is not present.

Responses are made with a 401 Unauthorized status along with WWW-Authenticate and X-OIDex headers:

   WWW-Authenticate: OIDExchange
   X-OIDex: key1="value1", key2="value2", key3="value3"

A "mode" key is always present, as described in the following sections. The order of the key-value pairs is not significant, except that if a given key appears more than once it is the latter value which is to be used. However, implementations SHOULD NOT include duplicate keys.

TODO: Describe this more formally.

HTTP Redirects

The user-accompanied requests in the Exchange protocol are performed by having the user's browser redirected to a new URL with arguments given in the query string.

The arguments are encoded in the standard form-urlencoded format used with HTML forms. Appending of arguments to an existing URL is done using the same conventions as given in[OpenID.authentication-2.0]. [FIXME: Where is this specified in the 2.0 spec?]

[FIXME: Do we want to use POST requests and form redirecting as recommended in Auth 2.0? The Auth integration mechanism will probably require this to be allowed, at least.]

Request Setup

In the first phase of an Exchange transaction, the consumer sets up its request with the endpoint and obtains a handle representing that request.

The Consumer initiates the transaction by making an HTTP request to the Endpoint URL. The request has included with it an Authorization header and an X-OIDex header containing the following key-value pairs:

mode
The mode for this request; the literal string "initiate".
user
An identifier URI for the user that will authorize this request.

For example:

   Authorization: OIDExchange
   X-OIDex: mode="initiate", user="http://bob.example.com/"

The rest of the HTTP request, including the method and headers, is defined by the dependent service.

If the Consumer recieves any of the HTTP redirect response codes (3xx) in response to this request, it SHOULD repeat the request at the new URL given in the Location header. However, a consumer MAY refuse to follow an unreasonably large chain of redirects. If any redirect responses are recieved, the URL that ultimately satisfies the request MUST be used when fetching the response in the Response phase.

If the Endpoint is able and willing to satisfy the request, it MUST return in an HTTP 401 Unauthorized response the following key-value pairs:

initiate_return
The mode for this request; the literal string "initiate".
transaction_handle
An opaque string that the Endpoint uses to identify this request.
permission_url
The URL at which the Endpoint will perform the Permissing Check phase of the transaction.

The transaction_handle must contain enough information such that the Endpoint will be able to carry out this request during the response phase. The content of this string is to be considered opaque by the Consumer.

If this Endpoint is able to determine immediately that it will be unable or unwilling to service this request regardless of successful user authentication, it MAY respond with a normal HTTP error response code.

If the Endpoint recieves a request with no appropriate Authorization header, it MAY respond in any way it sees fit. If there is no useful response in the absense of the OpenID Exchange protocol, the Endpoint MAY return a 401 Unauthorized response including an empty challenge as follows:

   WWW-Authenticate: OIDExchange
   X-OIDex: mode="challenge"

Permission Check

In the permission check phase, the Endpoint authenticates the user and asks for the user's permission to serve the request.

The Consumer now sends an HTTP redirect response to the user's browser to send it to the Endpoint URL. In this request, the following arguments are appended to the query string:

oidex.mode
The mode for this request; the literal string "check_permission".
oidex.transaction_handle
The opaque handle string returned from the Endpoint during the Request Setup phase.
oidex.return_to
The URL to redirect the browser to in order to respond to the Consumer.
oidex.realm
URL pattern the Provider SHALL ask the End User to trust; equivalent to openid.realm as specified in[OpenID.authentication-2.0]section 10.2.

The Endpoint must now authenticate the user against the identifier presented during the request setup phase. An Endpoint MUST support OpenID Authentication 2.0 ([OpenID.authentication-2.0]) for this process, but MAY support other authentication protocols as a fallback from or in preference to OpenID Authentication. How other protocols are discovered and selected is outside the scope of this specification.

The authentication process may determine a different identifier URI for the current user (for example, in OpenID Authentication's directed identity case); in this situation, the Endpoint must first ensure that this substitution is valid as per the relevant authentication specification and, if so, continue with the substitute URI identifying the user. If the substitution is determined to be invalid, it is to be treated as an authentication error.

Once the Endpoint has successfully authenticated the user, it will determine whether the user is permitted to authorize this exchange. If so, the Endpoint will use a mechanism such as HTML forms to request permission from the user. Once permission is granted, an affirmative response is returned to the Consumer via a HTTP redirect to the given return_to URL with the following query string arguments appended:

oidex.mode
The mode for this request; the literal string "permission_return".
oidex.transaction_handle
The opaque handle string representing this transaction.

In the event of an authentication error, or if the authenticated user does not have access to authorize this transaction, an additional oidex.error_message argument is included containing a human-readable error message.

If an error_message key is present in the response then the Consumer MUST abort the request and SHOULD display an error message to the user.

Integration with OpenID Authentication

If allowed by the dependent service, is is possible to carry out this phase in parallel to an OpenID Authentication request. In this case, the request and response query string arguments described above are included as extension parameters for the checkid_immediate or checkid_setup request.

For OpenID 1.1, the arguments have an "openid.oidex." prefix instead of the usual "openid.". For OpenID 2, the standard extensibility mechanism is used: an openid.ns.oidex parameter is included containing the namespace URI [TODO: insert namespace URI here], and the other arguments are encoded with an "openid.oidex." prefix. In the OpenID 2 case, the use of "oidex" as the namespace identifier is purely a convention, and it is the namespace URI which indentifies the arguments as belonging to this specification. [FIXME: Reword all this nonsense so it doesn't drivel on quite so much.]

In this case, the oidex.return_to and oidex.realm parameters MUST be omitted; these are instead assumed to be the equivalent to the values from the matching OpenID Authentication arguments.

The response parameters are likewise merged with the Authentication response parameters when forming the return redirect URL.

The other phases of the Exchange protocol are unchanged in this case.

Response

In the response phase the original request is carried out and the HTTP response returned.

Having gained permission from the user in phase 2, the Consumer can now carry out the authorized request. The Consumer makes an empty request to the Endpoint URL, including an Authorization header and the following key-value pairs:

mode
The mode for this request; the literal string "fetch_response".
transaction_handle
The opaque handle string representing this transaction.

The Consumer SHOULD use the same HTTP method that was used in the original request. For methods that require a request body, the Content-length header SHOULD be set to zero and no body data included. The Endpoint MUST ignore any other headers or body data included in the request.

The Endpoint must now carry out the request originally submitted in the first phase. The response is returned to the Consumer as a normal HTTP response with no additional header fields. As with the original request, the content of this response is undefined by this specification and will be defined by the dependent service.

Security and Implementation Considerations

Use of a secure channel between Consumer and Endpoint

The use of a secure channel (for example, SSL or TLS) for requests from Consumer to Endpoint is STRONGLY RECOMMENDED. Dependent services MAY, at their option, mandate the use of a secure channel.

Use of a secure channel for communication with the end-user's browser is also RECOMMENDED, to reduce the possibility of a compromised transaction_handle or a man-in-the-middle attack.

Disclosure of Request in transaction_handle

The content of the transaction_handle is undefined by this specification except to say that it must contain sufficient information for the request to be carried out in the response phase.

Some Endpoint implementations may chose to encode request data directly into the transaction_handle to avoid retaining this data as local state. This has several caveats, however:

  • The request data will be used twice in the query string of a request, which may lead to it being exposed via the browser History, proxy servers and logs. In many cases this will be undesirable and unexpected by the end-user.
  • It may be possible for the Consumer to alter the content of the request so that the user is tricked into authorizing a different request to the one that is eventually carried out.
  • There are practical limits on the size of the transaction_handle value due to its use in the URL query string and also due to the need for the Consumer to use the request_handle as a key representing the transacton.

It is strongly recommended to implement an Endpoint such that the transaction_handle is simply an opaque key mapping on to request data retained at the server. This handle should be sufficiently large and un-predictable as to avoid requests being intercepted by a third-party.

For practical implementation reasons, it is recommended that the transaction_handle be no longer than 255 bytes in length, since Consumer implementations are likely to use it as a database key and may be unable to retain a value longer than this. One alternative for Consumers is to use some kind of hash algorithm on the handle and use the result as a key, while retaining the full handle in an un-indexed column.

User Interface Guidelines

Note: This section is non-normative.

While this specification does not make any specific requirements on user interface, some guidelines are included here in the hope that they will be useful. Dependent services may impose other guidelines or requirements which augment or replace the guidelines given here.

During the permission check phase, the user should be given enough information about the request to make an informed decision about whether it should be carried out. Ideally, this should be presented in high-level terms based on knowledge of the dependent service. For example, a user profile exchange service may allow the Consumer to request a list of fields to be returned, in which case the Endpoint could include this list in natural language for the user to review before approving the request.

[FIXME: This section probably doesn't belong here.]

Early Authentication Sanity-Check

Note: This section is non-normative.

It may be desirable in some cases for an Endpoint to fail the request process early if it determines that there is no possibility that the request can be authorized by the identified user.

An Endpoint may do OpenID Discovery on the user identifer URI during the request setup phase to determine whether it is a valid OpenID identifier. It may also do an early check to see if the named user has access to authorize the request, though Endpoints must still do OpenID Discovery and allow for the use of directed identity and delegation.

[FIXME: This section probably doesn't belong here.]

Request Storage Optimization

Note: This section is non-normative.

Conceptually this protocol operates in terms of entire HTTP requests. However, in practice it is likely that an endpoint will be implementing only a specific dependent service.

As an optimisation, endpoints may wish to do request parsing and processing during the request setup phase making use of higher-level knowledge about the service in use. The can then retain only the necessary high-level details about the request against the transaction_handle.

However, the side effects of the request, if any, MUST NOT take place until the response phase.

[FIXME: This section probably doesn't belong here.]

Still to do...

This is an unfinished specification and as such there are several things left to do, including:

  • Spec up some example dependent services to ensure that this transport really solves the problems it intends to solve.
  • Tighten up the language and structure to make it more like a spec and less like a tutorial.