# FBAuth #

This gem provides authentication and basic Facebook functions for your Rails application.

## The Authentication Challenge ##

Facebook is an evolving platform, over the past couple years we’ve seen a lot of change in how it authenticates users of third-party applications.

The documentation for Facebook is minimal, without historic reference or in-depth discussion of the different implementation scenarios that our applications may take.

For example, the preferred method of doing “Canvas” applications, those that live within the Facebook “wrapper” is now to use an iFrame. If you choose to utilize the Javascript Connect SDK and rely on its authentication mechanisms this will fail under any browsers that block cross-domain cookies - which is more prominent as time goes on due to the security risks involved in allowing cross-domain cookies.

Therefore, as of this writing, applications using the prescribed iFrame style and using the JS SDK will fail on mobile Safari, Safari on Windows’ default settings, and various mobile implementations of the Android browser.

This plugin uses a few techniques to locate your “access token” and prefers to use the OAuth API to get what you need as a Facebook app to ensure your users have correctly added your app, authenticated in Facebook, and to communicate with the Graph and Query APIs.

Here are the scenarios we currently handle:

__iFrame Apps__

__External (Connect) Apps__

## Integration with Your Rails App ##

Add fbauth to your Gemfile

gem 'fbauth', '~> 1.0'

Create ‘config/facebook.yml`

development:
  app_id: 'xxxxxxxxxxxxx'
  app_context: 'my-app-dev'
  auth_path: '/login'
  canvas_url: 'http://dev.myapp.com/facebook'
  app_secret: 'xxxxxxxxxxxx'

test:
  app_id: 'fake_id'
  app_context: 'my-app'
  auth_path: '/login'
  canvas_url: 'http://myapp.com/facebook'
  app_secret: 'fake_secret'

production:
  app_id: 'xxxxxxxxxxxxx'
  app_context: 'my-app'
  auth_path: '/login'
  canvas_url: 'http://myapp.com/facebook'
  app_secret: 'xxxxxxxxxxxx'

Note: _We are assuming that you will be registering two facebook applications, one that you will be using to actively develop your application and the other for production use for your users._

Include the fbauth modules in your application controllers

include FacebookAuthFunctions
include FbauthHelper

In the controllers you want restricted to authorized users, or in your ‘Application` controller, add the filters

before_filter :require_facebook_auth

Create the controller and method that will live at your ‘auth_path` specified in your facebook.yml file.

class AuthController < ApplicationController

  # Use this if you've included FacebookAuthFunctions in your
  # Application controller...
  # skip_before_filter :require_facebook_auth

  def login
  end
end

And then create your login template (we use HAML, but you can use ERB if you want.

%div.fblogin
  You are not logged in to Facebook, please click here:
  %fb:login-button{:perms => 'publish_stream'} Log In to Facebook

%div.fbadd
  Please add this Application - it's great!
  %fb:login-button{:perms => 'publish_stream'} Add This Application

%div.fbready
  Please wait...

= fbauth_login_javascript(:login => '.fblogin', :add => '.fbadd', :ready => '.fbready')

The three areas noted above are exposed in the following scenarios:

## Using the Facebook APIs ##

### Graph API ###

The Graph API gives you the ability to request a great deal of information about individual social relationships and perform basic updates to that graph (ie. posting news-feed events).

Certain actions (posting changes, reading certain restricted attributes) are only available if you provide an access token and make an authenticated call.

__Unauthenticated Call__

graph = FacebookGraph.new
graph.call('svetzal')

This will retrieve publicly available information on the provided user’s Facebook UID or handle in a Ruby hash structure.

{"name"=>"Steven Vetzal", "gender"=>"male", "id"=>"849395216", "last_name"=>"Vetzal",
 "locale"=>"en_US", "link"=>"http://www.facebook.com/svetzal", "first_name"=>"Steven"}

__Authenticated Call__

graph = FacebookGraph.new(fbauth.access_token)
graph.call('svetzal', { :scope => "birthday" })

This will make a similar call but as an authenticated caller we can request a restricted scope, in this case information about the user’s birthday (if our app has requested the birthday permission from the user).

### Query API (FQL) ###

__Unauthenticated Call__

query = FacebookQuery.new
query.fql('SELECT name, first_name, last_name FROM user WHERE uid in ("849395216","58001611","1018515154")')

FQL is handy for performing multiple lookups at once, and can save you a lot of latency.

[
  {"name"=>"Steven Vetzal", "last_name"=>"Vetzal", "first_name"=>"Steven"},
  {"name"=>"Nate Smith", "last_name"=>"Smith", "first_name"=>"Nate"},
  {"name"=>"Craig Savolainen", "last_name"=>"Savolainen", "first_name"=>"Craig"}
]

__Authenticated Call__

query = FacebookQuery.new(fbauth.access_token)

__Manually Building an Access Token__

If you scan your logs, you’ll see the ‘signed_request` OAuth GET parameter being sent to your application. You can manually build yourself an authentication token from this using the following code.

data = FacebookDecoder.decode('{"signed_request"=>"oXWWpLi2tX7QW3cjX...(removed)"}')
fbauth = FacebookAuth.create(data)
fbauth.validate

The ‘.validate` step is optional, but pre-warns you if the token you are about to use is good. If it is not, you can find out why by looking at `fbauth.validation_error`.

# Things Remaining Unclear #

Documentation for the Facebook platform is a little fragmented, so we haven’t (that we recall) come across the answers to these questions yet:

# Change Log #

v1.2.0.4

v1.1.0.2

v1.0.0.2

v1.0.0.1

v1.0.0.0

v0.9.9.6