OmniAuth Facebook expired token error

2020-05-24 11:45发布

I am using OmniAuth to get access to Facebook in my app. I am using the fb_graph gem: https://github.com/nov/fb_graph to post to Facebook. I am running omniauth-0.3.0 on Heroku for this app. The token that I save when the user is created is changed when the user logs in sometime later.

Code for creating user

    class SessionsController < ApplicationController  
    def create  
     auth = request.env["omniauth.auth"]  
     user = User.find_by_provider_and_uid(auth["provider"], auth["uid"])||           
     User.create_with_omniauth(auth)
       session[:user_id] = user.id  
       redirect_to root_url, :notice => "Signed in!"  
         end 

The User model is:

  def self.create_with_omniauth(auth)  
    create! do |user|  
    user.provider = auth["provider"]  
    user.uid = auth["uid"]  
    user.name = auth["user_info"]["name"] 
    user.token = auth["credentials"]["token"]
    end
   end

I am now seeing this error on about 30% users-

 FbGraph::InvalidToken (OAuthException :: Error validating access token: Session does not match current stored session. This may be because the user changed the password since the time the session was created or Facebook has changed the session for security reasons.)

I saw that the expired token issue has been recently fixed in OmniAuth:

https://github.com/soopa/omniauth/commit/67bdea962e3b601b8ee70e21aedf5e6ce1c2b780

I used this code which tries to refresh the access token. However, I still get the same error. Can someone point to what I am missing? Is there some other way I could update the token every time the user logs in?

The only solution which has worked is to create a new User everytime the User logs in (I don't like this solution at all):

  def create  
    auth = request.env["omniauth.auth"] 
    user = User.create_with_omniauth(auth)
    session[:user_id] = user.id  
    redirect_to root_url, :notice => "Signed in!"  
  end

Thanks!

3条回答
趁早两清
2楼-- · 2020-05-24 12:32

I was using similar solution before you answered this question-

  class SessionsController < ApplicationController  
  def create  
 auth = request.env["omniauth.auth"]  
 user = User.find_by_provider_and_uid(auth["provider"], auth["uid"]) ||  User.create_with_omniauth(auth)  

 user.update_attributes(:token => auth["credentials"]["token"])

 session[:user_id] = user.id  
 redirect_to root_url, :notice => "Signed in!"  

  end
查看更多
迷人小祖宗
3楼-- · 2020-05-24 12:33

Can't we refresh the token using FBGraph gem with follwing method in such case?

auth = FbGraph::Auth.new(CLIENT_ID, CLIENT_SECRET)
auth.exchange_token! access_token # Needs fb_graph 2.3.1+
auth.access_token # => new token

However, This will not extend token's expiry but will replace token with new one. Expiry time will remain same. Checked it with FB, They may not allow to extend FB token expiry more than 60 days. Maximum token validity is 60-days.

reference: https://github.com/nov/fb_graph/wiki/Authentication#wiki-extend-token-expiry

查看更多
叼着烟拽天下
4楼-- · 2020-05-24 12:35

You can simply update the token when you create the session.

class SessionsController < ApplicationController  
def create  
  auth = request.env["omniauth.auth"]  
  user = User.find_by_provider_and_uid(auth["provider"], auth["uid"]).tap do |u|
           u.update_attributes(:token => auth["credentials"]["token"]) if u
         end || User.create_with_omniauth(auth)
  session[:user_id] = user.id  
  redirect_to root_url, :notice => "Signed in!"  
end 
查看更多
登录 后发表回答