Geek Blog for Little Red String

Geek stuff, amature programming, Linux, Ruby, open source

OpenIdAuthentication With remote_form_for

I finished putting in some sweet AJAXy goodness for comments on the Little Red String site only to find that OpenIdAuthentication was not going to work with remote_form_for. Really, I don’t think that OpenID is going to work with AJAX in general. I peeked inside of the OpenIdAuthentication library and noticed that whenever a user authenticates the redirect_to method is used.

# In module OpenIdAuthentication::begin_open_id_authentication
...
redirect_to(open_id_redirect_url(open_id_request, return_to, method))
...

Well redirect_to is not going to work with remote_form_for, but should everyone suffer? Yes.

No. I meant, “no”. RJS has it’s own little redirect_to method and with a classic respond_to block, we can add a little flexibility to the OpenIdAuthentication plugin to make it work if there is an AJAX request.

# Put this in vendor/open_id_authentication_hacks.
# This is compatable with version e6df78367b257886021785ba0260a4b5a4eca793
# of the plugin on 2/21/2008.
module MyOpenIdAuthentication
  private

  def begin_open_id_authentication(identity_url, options = {})
    identity_url = normalize_identifier(identity_url)
    return_to    = options.delete(:return_to)
    method       = options.delete(:method)

    options[:required] ||= []  # reduces validation later
    options[:optional] ||= []

    open_id_request = open_id_consumer.begin(identity_url)
    add_simple_registration_fields(open_id_request, options)
    add_ax_fields(open_id_request, options)

    # This is where my hack begins
    redirect_url = open_id_redirect_url(open_id_request, return_to, method)
    output = ''
    respond_to do |format|
      format.html {output = redirect_to(redirect_url)}
      format.js do
        render(:update) { |page| output = page.redirect_to(redirect_url) }
      end
    end
    output
    # This is where my hack ends

  rescue OpenIdAuthentication::InvalidOpenId => e
    yield Result[:invalid], identity_url, nil
  rescue OpenID::OpenIDError, Timeout::Error => e
    logger.error("[OPENID] #{e}")
    yield Result[:missing], identity_url, nil
  end
end

ActionController::Base.send :include, MyOpenIdAuthentication

This works pretty well. However, shouldn’t there be a way to perform the OpenID authentication asynchronously and only call redirect if the user has to actually visit their provider? Let me know in the comments.