Devise + Omniauth: disable email login when users enable SSO

398 Views Asked by At

I have a website that used a normal Devise login with email and password.

Then I have completed this tutorial to add Omniauth / SSO:

https://github.com/heartcombo/devise/wiki/OmniAuth:-Overview

Now when some users choose to use "Sign in with Google" I want to disable the normal login with email and password for those users (for enhanced security).

How can I achieve that?

2

There are 2 best solutions below

0
Jimmy Truong On

I'm facing in a similar situation and I'm not sure there's a clean way to do it.

I'm doing what krsyoung is suggesting on this thread https://github.com/heartcombo/devise/issues/5502#issuecomment-1445633830

# user.rb

  def valid_password?(password)
    return false if sso_enabled?

    super
  end

Extra: since I have to disallow unlock-ing accounts and resetting passwords but also have to obfuscate the validation messages by showing the default devise messages, I had to overwrite some more devise methods

# also in user.rb

  def send_reset_password_instructions?
    email_login_enabled? # your logic can go here
  end

  def send_reset_password_instructions
    # still show the `send_paranoid_instructions` message
    # "If your email address exists in our database, 
    # you will receive a password recovery link at your email 
    # address in a few minutes."
    return unless send_reset_password_instructions?

    super
  end

  def send_unlock_instructions?
    email_login_enabled?  # your logic can go here
  end

  def send_unlock_instructions
    # Still shows the `send_paranoid_instructions`
    # "If your account exists, you will receive an email 
    # with instructions for how to unlock it in a few minutes."
    return unless send_unlock_instructions?

    super
  end
0
Sharjeel On

active_for_authentication? (which you already know) method is used to control if devise should allow a user to login. If you return false for omniauth user then it will also disable login for omniauth user when user is trying to login using omniauth flow. So it's not an option.

Option 1:

active_for_authentication? does not know if user tries to login using password or omniauth. If we manage to know which flow is followed then we can return false when omniauth user tries to login using password.

One way to know which path is followed by setting session when user tries to login using omniauth flow and check for it in active_for_authentication?

In omniauth flow:

session[:omniauth_login] = true

and in active_for_authentication?

def active_for_authentication?
  super && (!omniauth_user? || session[:omniauth_login])
end

It will allow regular users to sign in, block omniauth users sign in by password and allow omniauth users to sign in using omniauth flow (where session is set.). Also reset session after login.

Option 2:

You can override sessions_controller and block access for omniauth enabled users.

class SessionsController < Devise::SessionsController
  def create
    #Allow login with password for all except omniauth users    
    #Define your own logic inside omniauth_user?

    if omniauth_user?(sign_in_params)                  
      redirect_to new_user_session_path, alert: "You can't login using password"
      return
    end

    super
  end
end