7

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 = "devise@myapp.host.com"

  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!

Chris Salij
  • 3,096
  • 5
  • 26
  • 43
Sebastian Roth
  • 11,344
  • 14
  • 61
  • 110
  • Just found this: http://stackoverflow.com/questions/4475726/devise-and-omniauth-remembering-oauth and will give it a try. – Sebastian Roth May 12 '11 at 13:22
  • And I found: https://github.com/plataformatec/devise/wiki/OmniAuth:-Overview .. so will try this out. Having big hopes.. – Sebastian Roth May 12 '11 at 13:24
  • Changed to a tighter integration with Devise, will edit the post and add the updated code. – Sebastian Roth May 13 '11 at 06:14
  • Added a bug report to Devise: https://github.com/plataformatec/devise/issues/1065 – Sebastian Roth May 13 '11 at 06:41
  • so, you removed the `session[:user]` stuff, replaced with `sign_in_and_redirect` from devise? Do you use the authorize_user! before filter, so that it redirects to the url you came from? who implements the `authenticate` in the routes file (tried without it)? – oma May 16 '11 at 08:36

3 Answers3

5

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

David Burrows
  • 5,217
  • 3
  • 30
  • 34
  • And that's where the error was. In fact I had (stupidly) cached something related to that. Your answer was a good hint. Thx. – Sebastian Roth Jun 20 '11 at 07:17
1

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.
Aditya Sanghi
  • 13,370
  • 2
  • 44
  • 50
0

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 ?

oma
  • 38,642
  • 11
  • 71
  • 99
  • Actually, I'm not using devise at all for the `User` object. This is a good hint and I will try to enable it, thus having the methods implemented by Devise. Session store: the default one defined in Rails 3. Logged out: Yes, logged out of my app - the controller will receive a current_user that is. – Sebastian Roth May 12 '11 at 13:06
  • Session store is: ./config/initializers/session_store.rb:14: MyApp::Application.config.session_store :cookie_store, :key => '_my_app_production_session' – Sebastian Roth May 12 '11 at 13:12
  • should be ok, I don't recommend cookie_store for security reasons, but it shouldn't have anything to do with this issue. What about accidently assigning `session[:user]= nil_result`, have you ruled out this possibility yet? – oma May 12 '11 at 13:52
  • Actually yes, ruled it out. The SessionController#create function is the only one setting session[:user_id] (except the #destroy function). (grepped for it). I'm continuing to check whether there are hidden calls to it, but cannot imagine that. logs are also not containing anything like that. – Sebastian Roth May 12 '11 at 13:54