diegopolido
Joined 4/7/2021
diegopolido said over 3 years ago on Two Factor Authentication :
Hey there! First of all, thanks a lot for this tutorial! I need some help:

I have an application that has a lot of instances with lot of users. Most of them got the proper process to enable 2FA. However, some of them didn't get to enable their accounts, forcing myself to allow the users to operate the system without 2FA. The problem is that Google Authenticator reads the QR Code properly but the code the user type to enable the account doesn't match and the process doesn't enable the 2FA. I did some test about to get user's codes and ran bunch of times user.otp_code to compare with user's codes:

Time  User's code   user.otp_code  
00s        542851    =>   154955
30s        154955    =>   674074
60s        674074    =>   998683
90s        998683    =>   another

Seems there's some delay between Google Authenticator and the gem. I tried to increase the drift to 120, but it didn't work. Some people are posting some comments on the gem github.

I appreciate your help!

diegopolido said over 3 years ago on Two Factor Authentication :
I asked my customer to try to use FreeOTP, he's read the QR code and he didn't get to enable the account. I have no clue what's happening.

diegopolido said over 3 years ago on Two Factor Authentication :
So, I was digging until I found some workaround for me: I added also drift_ahead on my verification by overriding the authenticate_otp to add the drift_ahead arg to ROTP::TOTP#verify:

# config/initializers/one_time_password_decorator.rb

ActiveModel::OneTimePassword::InstanceMethodsOnActivation.module_eval do
  def authenticate_otp(code, options = {})
    return true if backup_codes_enabled? && authenticate_backup_code(code)

    if otp_counter_based
      hotp = ROTP::HOTP.new(otp_column, digits: otp_digits)
      result = hotp.verify(code, otp_counter)
      if result && options[:auto_increment]
        self.otp_counter += 1
        save if respond_to?(:changed?) && !new_record?
      end
      result
    else
      totp = ROTP::TOTP.new(otp_column, digits: otp_digits)
      if drift = options[:drift]
        totp.verify(code, drift_behind: drift, drift_ahead: drift) # <= my change
      else
        totp.verify(code)
      end
    end
  end
end

That's will solve my problem for now! Thanks a lot!