Search code examples
ruby-on-railsrubyauthenticationomniauthomniauth-google-oauth2

Authenticated routes with Omniauth Google


I'm trying to make an authenticated route /me using omniauth-google-oauth2. So far, I have the library set up to login and logout and it's working fine. However, I want to have certain routes be accessible only when a user is logged in. I found this snippet and made some small changes to fit my set up.

application_controller.rb

before_filter :authenticate
def authenticate
    redirect_to :login unless User.from_omniauth(env["omniauth.auth"])
end

user.rb

def self.from_omniauth(auth)
    where(provider: auth.provider, uid: auth.uid).first_or_initialize.tap do |user|
        user.provider = auth.provider
        user.uid = auth.uid
        user.name = auth.info.name
        user.first_name = auth.info.first_name
        user.last_name = auth.info.last_name
        user.email = auth.info.email
        user.picture = auth.info.image
        user.oauth_token = auth.credentials.token
        user.oauth_expires_at = Time.at(auth.credentials.expires_at)
        user.save!
    end

I used env["omniauth"] because that's the auth hash I used in my SessionsController.

However, now whenever I go to localhost:3000, I get the following error:

undefined method `provider' for nil:NilClass

I'm assuming this happens because env["omniauth.auth"] is not accessible from application_controller.rb? If that's the case, then how do I properly access the auth hash?


Solution

  • Try this:

    application_controller.rb

    before_filter :authenticate
    
    def authenticate
      redirect_to :login unless user_signed_in?
    end
    
    def user_signed_in?
      !!current_user
    end
    
    def current_user
      @current_user ||= begin
        User.find(session[:current_user_id]) || fetch_user_from_omniauth
      end
    end
    
    def fetch_user_from_omniauth
      user = User.from_omniauth(env['omniauth.auth'])
      session[:current_user_id] = user.id
      user
    end
    

    This will first try to fetch the user already logged in (from session). If not found, it will try to create a user from omniauth and then set its id in session, so that for next requests, it does not need omniauth in env to find current user.