Friday, September 7, 2012

HTTParty Connecting to Rails With Devise Auth

So I needed to script a connection to a Rails server that uses devise authentication. Generally, you'd do that by creating an auth token in your devise db and send that as a parameter with your HTTP request.  This time, however, I just wanted connect to the site using an existing username and password.  I also wanted to use HTTParty as my client library, because, well, that's what we use around here. 

Devise tracks logged in users with a changing session key.  Since HTTParty doesn't really do session tracking, I thought I'd post some hacked code here.  If you know a better way, please feel free to comment.  You can also see why this is a bad idea to use in a codebase long term, so use auth tokens or something better asap.  (note clear credentials in the first line.)


params = {"user[email]"=>"myemail@mymail.cxx",
"user[password]"=>"lkjhlkjh"}
      default_params params
      response = get("#{SERVER}/users/sign_in")
                          
               #Get rails authenticity_token and sign in
        search = response.body.gsub(/\"authenticity_token\" type=\"hidden\" value=\".*?\"/)
        first=search.next
        authenticity_token = first.split("\"")[first.split("\"").length-1]
        params["authenticity_token"] = authenticity_token
        params["commit"] = "Sign in"
        response = post("#{SERVER}/users/sign_in",
                                 {:body=>params})

                   # get session cookie
        service_cookies = CookieHash.new
        # in the default case, the first value in cookies is the session cookie.  You may need to look through the cookies if the service sets a bunch.
        set_cookies.add_cookies response.headers["Set-Cookie"].split(";").first
        cookies(service_cookies)
        params["referrer"]= "#{SERVER}/users/sign_in"
        params.delete "authenticity_token"











        # Here's your first request
        response =
                  get("#{SERVER}/mypage.json?param=some_param")



        # now you need to get the next session cookie and send forward to next request.
        service_cookies = CookieHash.new
        set_cookies.add_cookies response.headers["Set-Cookie"].split(";").first
        cookies(set_cookies)
 
                   # next request
        response =
                  get("#{SERVER}/anotherpage.json?param=a_param")




That's it.  Adding in the authenticity token and continually passing the session cookie are the only tricky things.  Make sure to change over to a better method of auth if the script will be long lived.

Also, people have mentioned that something like mechanize is better for this type of thing.  Generally true, but method can help if you're in a hurry.