Setting up AOL's Open Auth with Ruby on Rails

Dec 20, 2011 Published by Tony Primerano

The current example on the AOL/AIM site leaves out details an functions. Here is my quick guide to using open auth with Ruby on Rails.

Step 1: Get a DEVID. For referer use http://yourhost:youport/auth/signin

Step 2: set DEVID in your environment.rb file to the value you were given

Step 3: Copy this controller (setup an index_url map in routes.rb or change references to index_url below)

class AuthController < ApplicationController

def signin
    redirect_to "http://api.screenname.aol.com/auth/login?devId=#{DEVID}&f=xml&succUrl=http://" + request.host + ':' + request.port.to_s + "/auth/signedin";
end

# this is where SUCCESSURL points
def signedin
    xml_data = params[:res]
    if xml_data.empty?
      # token fetch failed.  Try againa
      # will this work?  => redirect_to signin
      redirect_to "http://api.screenname.aol.com/auth/login?devId=#{DEVID}&f=xml&succUrl=http://" + request.host + ':' + request.port.to_s + "/auth/signedin";
    end

    token=""
    doc=REXML::Document.new(xml_data)
    doc.elements.each('response/data/token/a') do |t|
      token=t.text
    end

    session[:aim_token] = token #save in case we need more requests

    if token.empty?
      flash[:error] = "We had, ummm, a problem logging you in."
      redirect_to index_url
    end

    # We have the token.  Now lets get their loginId 
    url="http://api.screenname.aol.com/auth/getInfo?devId=#{DEVID}&f=xml&referer=#{referer()}&a="+token
    logger.info("getting " + url)

    req = handy_get(url,3)

    info_doc = REXML::Document.new(req[:body])
    login_id = ""

    info_doc.elements.each('response/data/userData/loginId') do |l|
      login_id = l.text
    end

    logger.info("login_id:")
    logger.info(login_id)

    if login_id.empty?
      flash[:error] = "Unable to get your screenname."
      redirect_to index_url
    else
      session[:login_id] = login_id

      #  We have the login Id.  Now we can access any 
      # local data we have about the user (Add DB code here if necessary)

      # if you were using a filter to protect sections of your site use these sessions to send them back
      if session[:intended_url]
        redirect_to session[:intended_url]
      else
        if session[:intended_action] && session[:intended_controller]
          redirect_to url_for(:controller => session[:intended_controller], :action => session[:intended_action])
        else
           redirect_to index_url
        end
      end
    end
  end
 private
 def referer
   return "http://" + request.host + ':' + request.port.to_s + "/auth/signin"
 end

   def handy_get(url,timeout=3)
    uri = URI.parse(url)
    http = Net::HTTP.new(uri.host,uri.port)
    path=uri.path
    if uri.query
      path=uri.path+"?"+uri.query
    end
    logger.info(["combined path:",path])
    g = Net::HTTP::Get.new(path)
    http.read_timeout = timeout
    begin
      res = http.start { |web|
        web.request(g)
      }
    rescue Timeout::Error
      return {
        :status => "fail",
        :body => ""
      }
    else
      logger.info(["g:",g])
      logger.info(["http:",http])
      logger.info(["res:",res])
      return {
        :status => "ok",
        :body => res.body
      }
    end
  end
end

Step 4: goto http://yourhost:yourport/auth/signin you should get a signin screen that redirects back to our site when done.
Step 5: Do something useful. Protect a controller

We'll also leverage the session[:intended_action] and session[:intended_controller] items referenced in the signedin function above.

Here we have an Admin controller that checks if the user is an admin using a filter. Currently it lets anyone who is authenicated in but you can fill in that code.  ;-)

class AdminController < ApplicationController

  before_filter :check_admin_auth

  def index
    render :text => 'welcome ' + session[:login_id]
  end

private
 def check_admin_auth
    unless session[:login_id]
      session[:intended_action] = action_name
      session[:intended_controller] = controller_name
      redirect_to :controller => 'auth', :action => 'signin'
    else
      # add logic here to check the login_id to see if is allowed to access
      # this area.  Where appropriate      
    end
  end
end

Step 6: goto http://yourhost:yourport/admin and you will either get the sign in screen or a welcome message if you are already signed in.
Step 7: Steal this code, make it better and share it