I'm currently reverse-engineering GitHub authentication with Rodauth for a screencast, and I implemented GitHub's 6-digit verification codes. What I did was rename the "key" column to "code" in account_verification_keys table, and wrote the following configuration:
class RodauthMain < Rodauth::Rails::Auth
configure do
verify_account_key_column :code
verify_account_key_param "code"
before_verify_account_route do
request.pass unless logged_in?
redirect "/" if rails_account.verified?
request.get { verify_account_view } # skip checking query params for verification key
end
account_from_verify_account_key do |code|
unless timing_safe_eql?(code, rails_account.verification_key.code)
verify_account_code_error "Invalid launch code."
end
if rails_account.verification_key.requested_at <= 24.hours.ago
regenerate_verify_account_code
verify_account_email_resend
verify_account_code_error "This launch code has expired. We've sent a new code to #{rails_account.email}."
end
account_from_session
end
verify_account_email_body do
"Continue signing up for GitHub by entering the code below: #{verify_account_key_value}\n\n" +
"Not able to enter the code? Paste the following link into your browser: #{verify_account_url(code: verify_account_key_value)}"
end
before_verify_account_email_resend { regenerate_verify_account_code }
end
private
def verify_account_code_error(message)
set_field_error("code", message)
set_response_error_status(422)
return_response verify_account_view
end
def regenerate_verify_account_code
rails_account.verification_key.update!(code: random_code, requested_at: Time.now)
end
def generate_verify_account_key_value
@verify_account_key_value = random_code
end
def random_code
6.times.map { rand(10) }.join
end
end
The verify account form had a code field:
<%= form.label :code, "Enter code", class: "form-label" %>
<%= form.number_field :code, value: params[:code], class: "form-control #{"is-invalid" if rodauth.field_error("code")}" %>
<div class="invalid-feedback"><%= rodauth.field_error("code") %></div>