Access token from devise+omniauth-facebook authentication for using in fb-graph
Asked Answered
T

3

7

I used devise and omniauth-facebook in my Rails 3 app for Facebook authentication, based on this tutorial: Adding Facebook auth to Rails 3.1 app, and it's working great!

But now I want to have full Facebook integration in my app, with which I can access the user's photos, friends, etc., and for that I am thinking of using fb_graph. fb_graph requires a token, and I wanted to know how to edit my user model to save the token and use it in fb_graph. Any help regarding this matter will be highly appreciated.

This is how my User model looks like right now:

class User < ActiveRecord::Base

# Include default devise modules. Others available are:
# :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
     :recoverable, :rememberable, :trackable, :validatable, :omniauthable

# Setup accessible (or protected) attributes for your model
  attr_accessible :email, :password, :password_confirmation, :remember_me

  has_many :photos
  has_many :scrapbooks

  def self.find_for_facebook_oauth(access_token, signed_in_resource=nil)
    data = access_token.extra.raw_info
    if user = User.where(:email => data.email).first
      user
    else # Create a user with a stub password.
      User.create!(:email => data.email, :password => Devise.friendly_token[0,20])
    end  
  end

  def self.new_with_session(params, session)
    super.tap do |user|
      if data = session["devise.facebook_data"] && session["devise.facebook_data"]["extra"]["raw_info"]
        user.email = data["email"]
      end
    end
  end
end
Tadtada answered 8/4, 2012 at 5:57 Comment(1)
Let's see this. Create Facebook model and store in that table but I don't sure that is the best way. :PEosinophil
P
9

You can do this:

User.create!(:email => data.email, :password => Devise.friendly_token[0,20], :authentication_token => access_token.credentials.token)

You will also need to add :authentication_token or whatever you named it to the attr_accessible

Ponder answered 11/4, 2012 at 10:1 Comment(3)
The only problem I am facing now is that the token gets expired. I deauthorized the app from my facebook for testing purposes, and now when I try to reauthorize myself, I get this error: OAuthException :: An active access token must be used to query information about the current user Is there any way I can refresh the token every time a user logs in to my app, to avoid the token from getting expired?Tadtada
Perhaps make a method in the user model that calls self.authentication_token = nil; self.save; during the deauth. Not sure how to handle this yet. In a few days I probably will.Ponder
Does somebody has an idea how the access token can be refreshed if you have more than one authentication provider (e.g facebook and twitter)? Example: the user always logs in with twitter, but he/she also has a connected facebook account. And after 60 days the facebook token expires. So how could I refresh all access_tokens at the same time?Babiche
T
3

I was looking for the same thing. I tried to implement James Robey{s answer and felt into the same error: OAuthException :: An active access token must be used to query information about the current user. Then I realized authentication_token was not being saved this way. After looking a while I found in FbGraph + OmniAuth + Facebook Graph API on Rails application a way to do it with session variables, by implementing the token saving during omniauth callback and then using it when calling fb_graph. So it might be something like this:

omniauth callback (app/controllers/users/omniauth_callbacks_controller.rb)

class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  def facebook
    @user = User.find_for_facebook_oauth(request.env["omniauth.auth"], current_user)

    if @user.persisted?
      flash[:notice] = I18n.t "devise.omniauth_callbacks.success", :kind => "Facebook"
# this part is where token is stored
        auth = request.env['omniauth.auth']
        token = auth['credentials']['token']
        session[:fb_access_token] = token
#
      sign_in_and_redirect @user, :event => :authentication
    else
      session["devise.facebook_data"] = request.env["omniauth.auth"]
      redirect_to new_user_registration_url
    end
  end
end

Then when calling fb_graph

@fb_user = FbGraph::User.new('me', access_token: session[:fb_access_token]).fetch

I don't know if it's the best way, but works so far.

Typo answered 22/6, 2012 at 0:37 Comment(2)
thank you for your answer. I have an additional question - how would the above handle refresh tokens?Shrove
@BKSpurgeon No idea, it was a patch solution. Sorry for the very late response.Servomechanical
G
1

ill refer you to https://github.com/nov/fb_graph/wiki/Page-Management

where nov states: You need the page’s access token to manage your page. Your (an user’s) access token doesn’t work here.

follow his link to the facebook developers site for more info

you'll need the users access_token and i do this through omniauth-facbook https://github.com/mkdynamic/omniauth-facebook

which you retrieve the use by first inputting this initializer into your app

Rails.application.config.middleware.use OmniAuth::Builder do
  provider :facebook, ENV['FACEBOOK_KEY'], ENV['FACEBOOK_SECRET'],
           :scope => 'email,user_birthday,read_stream', :display => 'popup'
end

(note you can change the permissions on the scope here check facebook developers login permissions for more

there are some inner workings to omniauth and omniauth-facebook but the jist is when you get the callback from facebook you have a rack omniauth hash from the request

omniauth = request.env["omniauth.auth"]

from that has you can access the users access token like this

facebook_user_token = omniauth['credentials']['token']

you can then feed that token into your fb_graph page call

page = FbGraph::Page.new('FbGraph').fetch(
  :access_token => facebook_user_token,
  :fields => :access_token
)

then you will simply be able to create a note by calling your desired method without a reference to the access token

note = page.note!(:subject => @title, :message => @message, :link => @url)
Greasepaint answered 9/5, 2013 at 8:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.