At the Forge - Integrating OpenID

Integrate OpenID into any Rails application, using off-the-shelf libraries and a bit of custom code.
Storing User Information

When we display this form in our browser, the user has one option—namely, to sign in with OpenID by entering a URL. The action (create) that is invoked has to find the user's OpenID server and redirect to that server. In order to do this, we need an instance of OpenID::Consumer, an object defined by the ruby-openid gem. Because we will continue to need this, we can create it as an instance variable:

def openid_consumer
 if @openid_consumer.blank?
   @openid_consumer =,

 return @openid_consumer

Notice that we're storing the OpenID information on the filesystem, in the tmp directory under the root of our Rails project directory. This is a bad idea when you have multiple Web servers, but is certainly good enough for a small or beginning site.

Now that we have a method named openid_consumer and an instance variable named @openid_consumer, we can implement the create action, to which our HTML form is going to be submitted:

def create
 # Get the OpenID parameter
 openid_url = params[:openid_url]

 # Make sure we got something
 if openid_url.blank?
   flash[:error] = "No OpenID was entered; try again"
   redirect_to :back

 # Get an OpenID response
 openid_response = openid_consumer.begin openid_url

 home_url = url_for :controller => "openid", :action => "index"
 complete_url = url_for :controller => "openid", :action => "complete"
 openid_redirect_url = openid_response.redirect_url(home_url, complete_url)
 redirect_to openid_redirect_url


In other words, we get the user's OpenID URL, and we check that it wasn't blank. Then, we use our instance of OpenID::Consumer to begin the OpenID login process, using open_consumer.begin, passing it the user's OpenID URL. If all goes well, this returns an instance of SuccessRequest, which also hands us the URL to which we should redirect the user. (If the request fails, the response will be a subclass of OpenIDStatus.)

Completing the Login Process

When we send the user to the user's OpenID server, we have to provide two different URLs as arguments: one that we're calling home_url, and the other that we're calling complete_url. The former is the root URL of our site; typically, it'll be a top-level URL. The latter, complete_url, tells the OpenID server to which URL the user should be redirected after logging in. In both cases, I use the built-in Rails url_for method, which constructs a URL out of a controller and action name.

When the user returns from the OpenID server, it will be to the URL indicated in complete_url. This means we have to define our complete method as well:

def complete
 home_url = url_for :controller => "openid", :action => "index"
 complete_url = url_for :controller => "openid", :action => "complete"

 openid_response = openid_consumer.complete(params, complete_url)

 session[:openid] = openid_response.identity_url
 flash[:error] = "You have been logged in as '#{session[:openid]}'"
 redirect_to :action => "new"

After defining home_url and complete_url once again, we invoke the complete method on our instance of OpenID::Consumer. If the response is good (and here we assume that it is, ignoring the possibility that we might have gotten an instance of OpenIDStatus back). Obviously, your real-life applications should include such a check.

Sure enough, when we put all this in place, it works! We can enter our user ID into the HTML form. We get verified by the user's OpenID server, even if that means another redirect. And, we get the user verified with basic information.