19

I'm using Koala gem on on Ruby on Rails application

And I have the following code on the model I'm using to the the data through Koala:

@graph = Koala::Facebook::GraphAPI.new(token_secret)
friends = @graph.get_connections("me", "friends")

where token_secret comes from a field of my users table, saved on the login.

It works fine but after a couple minutes I get:

Koala::Facebook::APIError (OAuthException: Error validating access token: Session has expired at unix time 1327438800. The current unix time is 1327442037.):

I found the way to renew this token in the front with the methods from the Facebook JS SDK but this method where I'm getting the list of friends is called on the controller.

How can I renew the token_secret using Koala? is this possible?

Raj
  • 22,346
  • 14
  • 99
  • 142
Mr_Nizzle
  • 6,644
  • 12
  • 55
  • 85
  • See this question http://stackoverflow.com/questions/6710425/how-do-you-renew-an-expired-facebook-access-token – Gazler Jan 24 '12 at 22:20

2 Answers2

22

I thought I'd answer this because it's something I just came across the need to do.

Koala added support for exchanging access tokens some time ago, here: https://github.com/arsduo/koala/pull/166

So my User model now has something like the following:

def refresh_facebook_token
  # Checks the saved expiry time against the current time
  if facebook_token_expired? 

    # Get the new token
    new_token = facebook_oauth.exchange_access_token_info(token_secret)

    # Save the new token and its expiry over the old one
    self.token_secret = new_token['access_token']
    self.token_expiry = new_token['expires']
    save
  end
end

# Connect to Facebook via Koala's oauth
def facebook_oauth
  # Insert your own Facebook client ID and secret here
  @facebook_oauth ||= Koala::Facebook::OAuth.new(client_id, client_secret)
end
sevenseacat
  • 24,699
  • 6
  • 63
  • 88
  • I'll try that one, looks really good. But before I try I still have a couple questions: 1. I'm using Graph API `@graph = Koala::Facebook::API.new(accessToken)`... can I use `exchange_access_token_info` there or should I have to use `Koala::Facebook::OAuth` instead? – Mr_Nizzle May 28 '13 at 14:52
  • `exhange_access_token_info` is defined on `Koala::Facebook::OAuth`, so yes you must use it there. – sevenseacat May 29 '13 at 02:44
  • 7
    I'd like to point out that in the above code (when I ran it just now with koala 1.6.0), new_token['expiry'] is a String of an integer number of seconds until the token expires ... you might want to convert it to a time when the token will expire if you're saving it. Something like (Time.now + new_token['expires'].to_i) HTH – Blake Miller Jun 16 '13 at 23:03
  • Could you explain to me where you're getting token_secret from? I save the auth.credentials.token into a user field and tried passing it in but I'm fairly certain your token_secret is a different thing – Michael Liu Mar 22 '14 at 15:39
  • @MichaelLiu it's not - it's the same token. – sevenseacat Mar 24 '14 at 01:37
  • I was being silly :P was trying to exchange an expired access token. – Michael Liu Mar 24 '14 at 16:27
  • @MichaelLiu Oooh yeah that could be a problem. I actually run a check on any access to Facebook that will call this method to refresh the token if the expiry is within a week, just to make sure it never expires. – sevenseacat Mar 25 '14 at 01:25
  • When I execute exchange_access_token_info, I only get this as a response: Refreshed token info: {"access_token"=>"CAADCTfxcFqgBACDfL..."}. Why is there no 'expires' data field? – Michael Liu Mar 27 '14 at 15:23
  • Are you sure that this methods works as intended? I receive new token but the 'expires' value decreases with time, so that `Time.now + new_token['expires'].to_i` actually points to the same initial token expire date... Do you have different behavior? – biomancer Jul 30 '14 at 15:15
  • Something may have changed in Facebook's API if it no longer returns an `expires` field. It did work when I wrote it - there's no reason to assume that the token you get back is different than the one you have, if the one you have is sufficiently valid (ie. it expires in a decent length of time). – sevenseacat Jul 31 '14 at 01:02
  • I'm a bit confused. Isn't the point to exchange the expired token... ? In this line `facebook_oauth.exchange_access_token_info(oauth_token)` I am getting the expired error `type: OAuthException, code: 190, error_subcode: 467` with this setup. it doesn't like me use my old `oauth_token` to exchange? (same as your `facebook_token`) – Clam Jan 20 '15 at 22:27
  • No. If the token is expired, the user must manually reauthorize it, by logging in again typically. The trick is to refresh tokens when theyre near expiry. – sevenseacat Jan 20 '15 at 23:07
  • I think @Clam is referring to `facebook_token_expired?` which implies the token expires before renewal. Perhaps `facebook_token_expiring?` would be better unless I misunderstand. – PhilT Feb 13 '15 at 07:03
  • Did you defined facebook_token_expired or it's some default method? – vaske Nov 22 '17 at 10:33
0

If you are trying to get the oauth_token for a Facebook website application, you need to use the redirect-based Oauth process. It's a little complicated. For a canvas app, it's simpler. You can still use the redirect-based process for a canvas app, but it's better to parse it from the signed_request.

Every time a user loads your app in Facebook, they will land on your first page with a "signed_request" parameter. This encrypted string must be parsed in your controller with a Koala object. From the result, you can get a new oauth_token which should be valid for about two hours. Here's how I do it.

 #Create a new koala Oauth object.
 oauth = Koala::Facebook::OAuth.new(APP_ID, APP_SECRET) 

 #Get the new oauth_token from the signed request.
 your_new_oauth_token = oauth.parse_signed_request(params[:signed_request])["oauth_token"]
ragingsquirrel3
  • 415
  • 3
  • 12
  • That's the problem, the application is not loading inside Facebook, It's just a web application using Facebook login, and at some point I use koala to retrieve the list of friends but if I don't load any other page on my app but the `friends` page the token is not updated, because I do this via `JS` on `FB.getLoginStatus(...)` – Mr_Nizzle Feb 20 '12 at 14:54