Pivotal Labs

Main menu

Skip to primary content
Skip to secondary content
  • About
  • Case Studies
  • Team
    • Executives
    • Locations
      • San Francisco (HQ)
      • Boston
      • Boulder
      • Denver
      • London
      • Los Angeles
      • New York
  • Community
    • Blogs
    • Tech Talks
    • Events
  • Careers
    • Lifestyle
    • Principles & Practices
    • Benefits
    • FAQ
    • Apply
  • Contact
    • Press Room
    • Press Releases
    • In The News
    • Press Kit
  • All
  • Labs
  • Standup
  • Tracker
John Barker

Facebook and GooglePlus Javascript SDK sign in with Devise + RoR

John Barker
Friday, January 18, 2013

Recently I added a modal sign in and sign up dialog to a Rails application that allowed for sign in using Facebook or Google as well as via email. This dialog can appear any time a user attempts to perform a protected action, allowing them to sign in and continue without losing any data.

To make this work I had to implement Google and Facebook sign in using the new javascript SDK provided for both platforms. The old style authentication redirects when successful which means any in memory session state is completely lost. This means forms are cleared, event handlers are rebound and any work in progress has to be done again.

Before I explain the difficulties we had getting this to work with I’ll explain briefly how OAuth works with respect to devise.

Typical OAuth workflow

Most sites implement this kind of workflow by opening a popup window pointing at their oauth request url (e.g: /oauth/facebook/). This sets up the initial state of the session using a cookie and redirects to the login page providing a url to it to redirect the user again once they’ve authenticated.

If authentication is successful, an oauth token is generated and stored in a cookie and the user is redirected to the callback url. The callback url hits the devise stack and verifies that the token is real by asking Facebook to verify it. If everything checks out execution dips into your application code and the user is created or looked up by some identifiable piece of information.

Client Side workflow

The new SDKs provided by Facebook and Google have changed this and allow for much greater flexibility. Facebook documents its new login workflow here http://developers.facebook.com/docs/howtos/login/getting-started/ and Google documents theirs here: https://code.google.com/p/google-api-javascript-client/wiki/Authentication.

Both APIs have a simple method which expects a callback. The callback is executed indicating whether authentication was successful and it’s up to you what you do with that information. This allows for greater flexibility and smoother transitions into an authenticated step.

Getting it to work with Devise

There are a number of gotchas with using the client side approach, some of them related to possible bugs and my difficulty in interpreting just how the OAuth devise gems work.

OAuth Gem Version

Omiauth OAuth2 version 1.1 recently introduced CSRF validation for the authentication workflow. Unfortunately this breaks client side validation since there is no request component.

For now I suggest downgrading those gems like so:

# NOTE: omniauth-oauth2 breaks client authentication, see here:
# https://github.com/intridea/omniauth-oauth2/issues/20
gem 'omniauth-oauth2', '~> 1.0.0'
# NOTE: omniauth-facebook 1.4.1 breaks SDK authentication, see here:
# https://github.com/mkdynamic/omniauth-facebook/issues/73
gem 'omniauth-facebook', '= 1.4.0'

The comments will give any future reader of your Gemfile an indication of what they need to do to lift the version restrictions on the omniauth dependencies.

Google OAuth2 Token Validation

The current omniauth-google-oauth2 gem will try to validate your access token with a different server and request format to the one required by the new javascript SDK. For the time being you can use our the forked version (here)[https://github.com/pivotal-geostellar/omniauth-google-oauth2/tree/client_login].

Performing Authentication

For the Facebook SDK I authenticate like so:

FB.login(function(response) {
  if(response.authResponse) {
    $.ajax({
      type: 'POST',
      url: '/users/auth/facebook/callback',
      dataType: 'json',
      data: {signed_request: response.authResponse.signedRequest}
      success: function(data, textStatus, jqXHR) {
        // Handle success case
      },
      error: function(jqXHR, textStatus, errorThrown {
        // Handle error case
      })});
  }
, scope: 'email'});

For Google:

var scope = 'https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile';
gapi.auth.authorize({client_id: 'client id', scope: scope}, function(result) {
    if(result && !result.error) {
      $.ajax({
        type: 'POST',
        url: '/users/auth/google_oauth2/callback',
        data: {code: result},
        dataType: 'json',
        success: function(data, textStatus, jqXHR) {
          // Handle authorized case
        },
        error: function(jqXHR, textStatus, errorThrown) {
          // Handle error case
        }
      });
    } else {
      // Handle unauthorized case
    }
});

Both of these calls hit the OAuth callback endpoint to verify the access tokens obtained by the user. If authentication succeeds you’ll get the typical devise+OAuth workflow and a session omniauth.auth cookie with the appropriate details.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Ken Mayer

[Standup][sf] 2011-05-16 Too much cowbell

Ken Mayer
Monday, May 16, 2011

Needful Things; Help

  • How to test command line applications? Use the old stand-by, expect, patch into the highline library, or the new hotness, aruba (CLI steps for Cucumber).

Very Interesting Things

  • fbAsyncInit does not fire when Facebook is really ready, only kind of sorta, maybe ready.
  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Abhijit Hiremagalur

Standup 08/03/2010: Bundle me this Batman!

Abhijit Hiremagalur
Tuesday, August 3, 2010

Ask for Help

  • I asked if there’s a date library in Ruby as rich as Java’s JODA

Suggestions included Chronic and RI_CAL though I’m hoping for something that can represent arbitrary periods (ranges?) of time JODA and handles interval calculation and other such date/time arithmetic.

  • is(‘:visible’) doesn’t always work as expected in Jasmine

One project reported that using this to as part of a Jasmine spec to ensure that an element becomes visible doesn’t appear to be reliable.

  • Annotate and Git History failed for a team using Rubymine 2.0.2 and git 1.7.2.1 in combination with svn.

They solved the problem by downgrading to git 1.7.1.1:

I followed instructions here to create a local set of portfiles:

http://guide.macports.org/#development.local-repositories and grabbed the older portfile from here:

https://trac.macports.org/browser/trunk/dports/devel/git-core?rev=69357

After I could do a port search git-core and have 1.7.1.1 show up, I was able to sudo port deactivate git-core @1.7.2_0+doc+svn and sudo port install git-core @1.7.1.1+doc+svn

  • One person was experienced compile errors when installing memprof on Ubuntu, fortunately somebody else had gotten this working before and offered to help him through thee.
  • A team noticed that Bundler ran multiple (4) times on CI taking nearly 11mins overall and wanted to know to make Bundler run only once

It was suggested that the problem may be due to the way they’d setup their preinitializer.rb and they should move the bundle install into a Rake task.


if ENV['IS_CI_BOX']
puts "IS_CI_BOX is set, running bundle install..."

system(‘bundle install’) || raise(“‘bundle install’ command failed. Install bundler with gem install bundler.”)

end

It was pointed out that they should make sure their Gemfile.lock file is checked into version control, which it was. Additionally Bundler 1.0.0 RC1 will allow isolating gems to a local path using bundle install path --disable-shared-gems

Interesting Things

  • The Facebook Graph API doesn’t appear to implement OAuth 2.0 properly/completely so it doesn’t work with the OAuth2 gem
  • One Pivot noticed that the version of ImageMagick installed on the default EngineYard solo image is out of date and had to upgrade this manually.
  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Pivotal Labs

When 2,147,483,647 just isn't enough.

Pivotal Labs
Wednesday, August 12, 2009

If only I had a paid a little more attention to any of the Facebook is growing more quickly than the Universe is expanding articles of late, I might have caught a bug in my app before I received multiple one star ratings.

That said, live and learn and be sure to create the uid column in your users table as a bigint.

t.integer :uid, :limit => 8

I will never know how many countless Facebookers with excessively large uids tried to play my game in vain, only to watch as MySQL mercilessly truncated their unique identifier to the eighth Mersenne prime.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter

Topics

  • agile (781)
  • rails (113)
  • testing (88)
  • ruby (83)
  • ruby on rails (70)
  • jobs (62)
  • javascript (55)
  • techtalk (44)
  • rspec (38)
  • ironblogger (32)
  • productivity (30)
  • activerecord (29)
  • gogaruco (29)
  • git (28)
  • nyc (27)
  • rubymine (26)
  • bloggerdome (23)
  • mobile (22)
  • process (21)
  • pivotal tracker (21)
  • cucumber (20)
  • design (19)
  • jasmine (19)
  • ios (18)
  • webos (17)
  • objective-c (17)
  • android (16)
  • tracker ecosystem (16)
  • palm (16)
  • "soft" ware (16)
  • fun (15)
  • ci (15)
  • cedar (15)
  • rails3 (14)
  • performance (14)
  • bdd (14)
  • gem (13)
  • css (13)
  • tdd (13)
  • selenium (12)
  • goruco (12)
  • bundler (12)
  • meetup (11)
  • railsconf (11)
  • nyc-standup (11)
  • capybara (10)
  • mac (10)
  • mojo (10)
  • chef (10)
  • api (10)
Subscribe to facebook Feed
  • About
  • Case Studies
  • Team
  • Community
  • Careers
  • Contact
  • Labs
  • Events

Contact Us

contact@pivotallabs.com
+1 415-77-PIVOT
TwitterLinkedInFacebook

Pivotal Tracker

Tracker is the award-winning agile project management tool that enables real-time collaboration around a shared, prioritized backlog.
Visit pivotaltracker.com >