Sebastian Roth
Sebastian Roth

Reputation: 11537

Omniauth+Facebook lost session

In a recent project, facebook Users can login using their Facebook UID to upload picture submissions based on file uploads or uploads from their personal albums etc.

Everything works quite nice on my local system in the development environment. Login via Facebook, Logout, Upload - all great.

In production though I'm facing a unknown and hard to debug problem. It seems that every once in a while (actually reproducable when uploading a new Submission to the system) the session is lost, the picture is NOT uploaded and the facebook user is logged out (!).

I'm using devise and omniauth. Omniauth is integrated into Devise.

Following is all the code that touches Devise/Omniauth or the User.

app/models/user.rb

class User < ActiveRecord::Base
  devise :omniauthable, :rememberable, :omniauth_providers => [:facebook]

  def self.create_with_omniauth(auth)
    u = User.find_by_uid(auth["uid"])
    return u unless u.nil?

    create! do |user|
      user.provider = auth["provider"]
      user.uid = auth["uid"]
      user.name = auth["user_info"]["name"]
      user.email = auth['user_info']['email']
    end
  end

  def after_signin_path
    '/competition'
  end
end

Database contains all needed fields for :rememberable, I hope.

app/controllers/users/omniauth_callbacks_controller.rb

class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  def facebook
    # You need to implement the method below in your model
    @user = User.create_with_omniauth(env["omniauth.auth"])

    if @user.persisted?
      flash[:notice] = I18n.t "devise.omniauth_callbacks.success", :kind => "Facebook"
      @user.update_attributes!(:current_auth_token => env["omniauth.auth"]['credentials']['token'], :last_language => I18n.locale.to_s, :updated_at => Time.now, :remember_created_at => Time.now)

      sign_in_and_redirect(:user, @user)    
    else
      redirect_to '/competition'
    end
  end

protected
  def after_omniauth_failure_path_for resource
    '/competition'
  end
end

config/initializers/devise.rb

OmniAuth.config.full_host = "http://#{APP_CONFIG[:domain]}"

Devise.setup do |config|
  config.mailer_sender = "[email protected]"

  require 'devise/orm/active_record'

  config.stretches = 10

  config.encryptor = :bcrypt
  config.timeout_in = 3.days

  config.pepper = "2a4b8b2ed9e12e553a7a542176f2ace1af62c062f3ba203a590b8b6307f33042b394922807a840004a3dcdf1c4e97ae085fe2c29654ddaeab7c60f431a8078abb"

  config.omniauth :facebook, APP_CONFIG[:facebook_app_id], APP_CONFIG[:facebook_app_secret], {
    :scope => "email,user_photos,user_photos,publish_stream,offline_access",
    :client_options => {
      :ssl => {
        :ca_file => "/etc/pki/tls/certs/ca-bundle.crt"
      }
    }
  }
end

There are no auth-related methods in application_controller.rb.

routes.rb:

The interesting part below:

  devise_for :users, :controllers => { :omniauth_callbacks => "users/omniauth_callbacks" }

  match '/logout_fb' => 'start#logoutfb'

  authenticate :user do
    get '/users/connect/:network', :to => redirect("/users/auth/%{network}")
  end

Somehow I cannot get to understand the authenticate block, which according to another post should be helpful.. ideas on this too?

So many theories: One is that the facebook function in the omniauth_callbacks_controller runs aside of the users' session, and hence sign_in_and_redirect won't work. So I had the idea of redirecting to another page like '/auth?uid=xxx' but this sounds both wrong, insecure and not stable.

Any help or hints are appreciated!

Upvotes: 7

Views: 3080

Answers (3)

David Burrows
David Burrows

Reputation: 5247

A bit of a long shot but try turning off protect_from_forgery - I had some issues with sessions disappearing and it turned out to be the issue discussed here https://github.com/intridea/omniauth/issues/203

Upvotes: 5

oma
oma

Reputation: 40770

You are using devise but you are not using it's own helpers. For instance, you've defined your own current_user method. To be honest, I can't see any obvious mistakes you've made, so it's just a desperate tip.

what kind of a session store do you use locally and what in production?

When you say "facebook user is logged out", this user is still logged in to facebook, but lost his session at yourapp.com ?

Are you sure that user.id is never nil or that you anywhere else than in .destroy set session[:user_id]= some_nil_variable ?

Upvotes: 0

Aditya Sanghi
Aditya Sanghi

Reputation: 13433

In my config/initializers/omniauth.rb, I had to add the following:

OmniAuth.config.full_host = "http://yourdomain.com" # Or have an environment specific URL.

Upvotes: 1

Related Questions