NOTE / OTP

Email OTP

Verify email by otp

Verify Email by send OTP code (Rails)


Prepare package

Send otp to email


  def send_otp_to_email
    respond_to do |format|
      format.json  do
        redis = Redis.new
        if redis.ttl("email-otp-#{params[:email]}") > (300 - 60)
          render json: { success: true, message: 'Already send otp code to email, please wait a moment' }
          return
        end
        otp_secret = ROTP::Base32.random
        totp = ROTP::TOTP.new(otp_secret, issuer: 'Validate Email otp')
        otp = totp.now

        redis.set("email-otp-#{params[:email]}", otp_secret)
        # send otp mail to user
        # MailWorker.perform_async(Mailer, :send_otp_to_email, { email: params[:email], otp: otp })
        render json: { success: true, message: "Already send otp code to your email, please checkout" }
      end
    end
  end


Explain:

  1. redis.ttl("email-otp-#{params[:email]}") > (300 - 60) we need to cauclate time, when first time send mail, and default time is 5 minutes
  2. otp_secret = ROTP::Base32.random Generating a Base32 Secret key
  3. totp = ROTP::TOTP.new(otp_secret, issuer: 'Validate Email otp') we use rotp get otp code by otp_secret
  4. otp = totp.now get otp code
  5. redis.set("email-otp-#{params[:email]}", otp_secret) we need to save temp token, we will use it later for validate


Verify otp

  def verify_otp
    redis = Redis.new
    otp_secret = redis.get("email-otp-#{params[:email]}")

    if otp_secret.nil?
      render json: { success: false }
      return
    end

    totp = ROTP::TOTP.new(otp_secret, issuer: 'Validate Email otp')
    if totp.verify(params[:otp], drift_behind: 300)
      token = SecureRandom.base58(20)
      redis.setex("otp-token-#{params[:email]}", 5.minutes, token)

      render json: { success: true, token: token }
    else
      render json: { success: false }
    end
  end


Explain:

  1. otp_secret = redis.get("email-otp-#{params[:email]}") get otp_secret for verify
  2. totp = ROTP::TOTP.new(otp_secret, issuer: 'Validate Email otp') we use rotp verify otp code by otp_secret
  3. totp.verify(params[:otp], drift_behind: 300) verify otp code, set 5 minutes expired
  4. token = SecureRandom.base58(20) generate random token
  5. redis.setex("otp-token-#{params[:email]}", 5.minutes, token) set token for your application

REFERENCE / 1

Loading