I'm writing a Rails app that uses omniauth-facebook to authenticate the user against FB (and to get a FB OAuth access token for the user). The app then uses Koala to make various calls to the FB Graph API, using that saved OAuth token.
I update the saved token each time the user re-authenticates (typically when they log in to my app). Even so, that saved token will expire (or otherwise become invalid) from time to time.
What's the best practice around guarding against auth failures and updating the token while using Koala?
Should all calls be wrapped in begin/rescue blocks, with an exception handler that re-authenticates the user against FB?
Is there some way (using Koala) to take advantage of the 'extending access tokens' process described here? If not, are there best practices on writing my own code to extract the new token myself from a Koala call?
When your app uses Facebook Login to authenticate someone, it receives a User access token. If your app uses one of the Facebook SDKs, this token lasts for about 60 days. However, the SDKs automatically refresh the token whenever the person uses your app, so the tokens expire 60 days after last use.
An access token is an opaque string that identifies a user, app, or Page and can be used by the app to make graph API calls. When someone connects with an app using Facebook Login and approves the request for permissions, the app obtains an access token that provides temporary, secure access to Facebook APIs.
What I have is a before_filter that is triggered on every page that requires an active Facebook session. Something like this should work:
before_filter :reconnect_with_facebook
def reconnect_with_facebook
if current_account && current_account.token_expired?(session[:fb]["expires"])
# re-request a token from facebook. Assume that we got a new token so
# update it anyhow...
session[:return_to] = request.env["REQUEST_URI"] unless request.env["REQUEST_URI"] == facebook_request_path
redirect_to(with_canvas(facebook_request_path)) and return false
end
end
The token_expired? method looks like this:
def token_expired?(new_time = nil)
expiry = (new_time.nil? ? token_expires_at : Time.at(new_time))
return true if expiry < Time.now ## expired token, so we should quickly return
token_expires_at = expiry
save if changed?
false # token not expired. :D
end
I came across this post which adapts code from the Railscast on Facebook to show how you can exchange the short-lived token for the 60-day one:
user.rb
def self.from_omniauth(auth)
# immediately get 60 day auth token
oauth = Koala::Facebook::OAuth.new(ENV["FACEBOOK_APP_ID"], ENV["FACEBOOK_SECRET"])
new_access_info = oauth.exchange_access_token_info auth.credentials.token
new_access_token = new_access_info["access_token"]
# Facebook updated expired attribute
new_access_expires_at = DateTime.now + new_access_info["expires_in"].to_i.seconds
where(auth.slice(:provider, :uid)).first_or_initialize.tap do |user|
user.provider = auth.provider
user.uid = auth.uid
user.name = auth.info.name
user.image = auth.info.image
user.email = auth.info.email
user.oauth_token = new_access_token #originally auth.credentials.token
user.oauth_expires_at = new_access_expires_at #originally Time.at(auth.credentials.expires_at)
user.save!
end
end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With