Skip to content

Social Login with Phonegap, Omniauth, Tokens, and InAppBrowser

For a project I needed to integrate Facebook and Twitter logins to a phonegap app.  I went through a ton of plugins and jsOAuths, but they were all quite cumbersome. I really wanted a simpler approach that would handle Twitter and Facebook at the same time.

This article about Twitter integration with Child Browser got me started in the right direction.  It’s a little dated with Child Browser, so I set out to update it to work with InAppBrowser, but during the process I realized that I could actually handle this issue a lot simpler.  Mostly because I only needed to login and didn’t require any deeper integration with Social platforms.

So after a little more digging I came across this lovely article on cross window communication with InAppBrowser which was everything I needed to take care of business!

In my case, the server is going to be doing all the heavy lifting, and for this project we already had Omniauth set-up for social login and tokens so I only needed to make a few tweaks to get this rolling.

The first tweak was to get it to output JSON for the App.  Out of the box Omniauth will keep track of your params, so I made it return a JSON response when I requested it in the query string like so “/users/auth/facebook?json=true”

Just for example, here how it would look if you were using the standard facebook action for omniauth:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  def facebook
    @user = User.from_omniauth(request.env["omniauth.auth"])
 
    if @user.persisted?
      sign_in @user, :event => :authentication #this will throw if @user is not activated
    else
      session["devise.facebook_data"] = request.env["omniauth.auth"]
      return redirect_to new_user_registration_url
    end
 
    return render :json => current_user if request.env["omniauth.params"]["json"]
 
    set_flash_message(:notice, :success, :kind => "Facebook") if is_navigational_format?
    redirect_to "/"
  end
end

The important parts here are:

  • I’m using “sign_in” instead of “sign_in_and_redirect” so I can handle the redirection later down the line.
  • Then I’m adding in “return render :json => current_user if request.env[“omniauth.params”][“json”]” so the callback will output the current user in JSON.

In my case the JSON output for current_user includes a token I can use to integrate with the API.

With that all set you’re ready to capture that JSON in phonegap:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
win = window.open(base_url+'/users/auth/facebook?json=true', '_blank', 'location=yes,enableViewPortScale=yes');
win.addEventListener('loadstop', function (e) {
  if (e.url.indexOf(base_url) >= 0 && e.url.indexOf('callback') >= 0) {
    win.executeScript(
      { code: "document.body.innerHTML" },
      function(values) {
        r = values[0];
        r = r.replace(r.substring(0, r.indexOf('{')),"").replace(r.substring(r.indexOf('}'),r.length).replace(/}/g,''),"");
        r = jQuery.parseJSON(r);
        //now r.api_token is available to use however you need in your app
        win.close();
      }
    );
  }
});

This works by:

  1. First opening a window with the social login page “/users/auth/facebook?json=true
    on my app base_url is the domain of the API, like http://api.google.com for example.
  2. Next I’m listening for every-time the page in InAppBrowser finishes loading with “addEventListener(‘loadstop‘”
  3. Then I’m waiting for the URL to have my API’s domain name plus “callback” here “if (e.url.indexOf(base_url) >= 0 && e.url.indexOf(‘callback’) >= 0) {
  4. Once there I use “executeScript” to fetch the document body, which is returned as values[0].
  5. Then I clean the return value of any HTML using replace and substring, then parse that to JSON

After that you can use that token in your App however you need to integrate with your API.

Published inJavaScriptRoRScripting

Be First to Comment

Leave a Reply

Your email address will not be published. Required fields are marked *