diff --git a/app/controllers/concerns/two_factor_authenticatable_methods.rb b/app/controllers/concerns/two_factor_authenticatable_methods.rb index a645776f312..9c70b576be4 100644 --- a/app/controllers/concerns/two_factor_authenticatable_methods.rb +++ b/app/controllers/concerns/two_factor_authenticatable_methods.rb @@ -161,7 +161,7 @@ def track_mfa_method_added mfa_user = MfaContext.new(current_user) mfa_count = mfa_user.enabled_mfa_methods_count analytics.multi_factor_auth_added_phone(enabled_mfa_methods_count: mfa_count) - Funnel::Registration::AddMfa.call(current_user.id, 'phone') + Funnel::Registration::AddMfa.call(current_user.id, 'phone', analytics) end def handle_valid_otp_for_authentication_context diff --git a/app/controllers/two_factor_authentication/otp_verification_controller.rb b/app/controllers/two_factor_authentication/otp_verification_controller.rb index e3996c60f58..f8747294520 100644 --- a/app/controllers/two_factor_authentication/otp_verification_controller.rb +++ b/app/controllers/two_factor_authentication/otp_verification_controller.rb @@ -98,6 +98,8 @@ def analytics_properties phone_fingerprint: Pii::Fingerprinter.fingerprint(parsed_phone.e164), phone_configuration_id: user_session[:phone_id] || current_user.default_phone_configuration&.id, + in_multi_mfa_selection_flow: in_multi_mfa_selection_flow?, + enabled_mfa_methods_count: mfa_context.enabled_mfa_methods_count, } end end diff --git a/app/controllers/users/additional_mfa_required_controller.rb b/app/controllers/users/additional_mfa_required_controller.rb index a451a659104..ab79d2998d5 100644 --- a/app/controllers/users/additional_mfa_required_controller.rb +++ b/app/controllers/users/additional_mfa_required_controller.rb @@ -19,6 +19,13 @@ def skip ).call end analytics.non_restricted_mfa_required_prompt_skipped + # should_count as complete as well + analytics.user_registration_mfa_setup_complete( + mfa_method_counts: mfa_context.enabled_two_factor_configuration_counts_hash, + enabled_mfa_methods_count: mfa_context.enabled_mfa_methods_count, + pii_like_keypaths: [[:mfa_method_counts, :phone]], + success: true, + ) redirect_to after_sign_in_path_for(current_user) end @@ -28,6 +35,10 @@ def enforcement_date @enforcement_date ||= IdentityConfig.store.kantara_restriction_enforcement_date end + def mfa_context + @mfa_context ||= MfaContext.new(current_user) + end + def confirm_user_fully_authenticated unless user_fully_authenticated? return confirm_two_factor_authenticated(sp_session[:request_id]) diff --git a/app/controllers/users/backup_code_setup_controller.rb b/app/controllers/users/backup_code_setup_controller.rb index 8cd48955eba..43e6ee64f4e 100644 --- a/app/controllers/users/backup_code_setup_controller.rb +++ b/app/controllers/users/backup_code_setup_controller.rb @@ -29,6 +29,7 @@ def edit; end def continue flash[:success] = t('notices.backup_codes_configured') + analytics.multi_factor_auth_setup(**analytics_properties) redirect_to next_setup_path || after_mfa_setup_path end @@ -54,7 +55,7 @@ def track_backup_codes_created analytics.backup_code_created( enabled_mfa_methods_count: mfa_user.enabled_mfa_methods_count, ) - Funnel::Registration::AddMfa.call(current_user.id, 'backup_codes') + Funnel::Registration::AddMfa.call(current_user.id, 'backup_codes', analytics) end def mfa_user @@ -111,5 +112,14 @@ def authorize_backup_code_disable return if MfaPolicy.new(current_user).multiple_non_restricted_factors_enabled? redirect_to account_two_factor_authentication_path end + + def analytics_properties + { + success: true, + multi_factor_auth_method: 'backup_codes', + in_multi_mfa_selection_flow: in_multi_mfa_selection_flow?, + enabled_mfa_methods_count: mfa_context.enabled_mfa_methods_count, + } + end end end diff --git a/app/controllers/users/piv_cac_authentication_setup_controller.rb b/app/controllers/users/piv_cac_authentication_setup_controller.rb index 90d610f2923..e6b74b7aa17 100644 --- a/app/controllers/users/piv_cac_authentication_setup_controller.rb +++ b/app/controllers/users/piv_cac_authentication_setup_controller.rb @@ -84,7 +84,8 @@ def piv_cac_service_url_with_redirect def process_piv_cac_setup result = user_piv_cac_form.submit - analytics.multi_factor_auth_setup(**result.to_h) + properties = result.to_h.merge(analytics_properties) + analytics.multi_factor_auth_setup(**properties) if result.success? process_valid_submission else @@ -121,7 +122,7 @@ def track_mfa_method_added analytics.multi_factor_auth_added_piv_cac( enabled_mfa_methods_count: mfa_user.enabled_mfa_methods_count, ) - Funnel::Registration::AddMfa.call(current_user.id, 'piv_cac') + Funnel::Registration::AddMfa.call(current_user.id, 'piv_cac', analytics) end def piv_cac_enabled? @@ -150,6 +151,13 @@ def good_nickname name.present? && !PivCacConfiguration.exists?(user_id: current_user.id, name: name) end + def analytics_properties + { + in_multi_mfa_selection_flow: in_multi_mfa_selection_flow?, + enabled_mfa_methods_count: mfa_context.enabled_mfa_methods_count, + } + end + def cap_piv_cac_count return unless IdentityConfig.store.max_piv_cac_per_account <= current_cac_count redirect_to account_two_factor_authentication_path diff --git a/app/controllers/users/piv_cac_setup_from_sign_in_controller.rb b/app/controllers/users/piv_cac_setup_from_sign_in_controller.rb index 3b8594bfdc3..19d3cb5eebc 100644 --- a/app/controllers/users/piv_cac_setup_from_sign_in_controller.rb +++ b/app/controllers/users/piv_cac_setup_from_sign_in_controller.rb @@ -35,7 +35,8 @@ def render_prompt def process_piv_cac_setup result = user_piv_cac_form.submit - analytics.multi_factor_auth_setup(**result.to_h) + properties = result.to_h.merge(analytics_properties) + analytics.multi_factor_auth_setup(**properties) if result.success? process_valid_submission else @@ -66,5 +67,12 @@ def process_valid_submission create_user_event(:piv_cac_enabled) redirect_to login_add_piv_cac_success_url end + + def analytics_properties + { + in_multi_mfa_selection_flow: false, + enabled_mfa_methods_count: MfaContext.new(current_user).enabled_mfa_methods_count, + } + end end end diff --git a/app/controllers/users/totp_setup_controller.rb b/app/controllers/users/totp_setup_controller.rb index 7abb664d231..0044f3d698c 100644 --- a/app/controllers/users/totp_setup_controller.rb +++ b/app/controllers/users/totp_setup_controller.rb @@ -24,7 +24,8 @@ def new def confirm result = totp_setup_form.submit - analytics.multi_factor_auth_setup(**result.to_h) + properties = result.to_h.merge(analytics_properties) + analytics.multi_factor_auth_setup(**properties) if result.success? process_valid_code @@ -97,7 +98,7 @@ def create_events analytics.multi_factor_auth_added_totp( enabled_mfa_methods_count: mfa_user.enabled_mfa_methods_count, ) - Funnel::Registration::AddMfa.call(current_user.id, 'auth_app') + Funnel::Registration::AddMfa.call(current_user.id, 'auth_app', analytics) end def process_successful_disable @@ -140,5 +141,12 @@ def cap_auth_app_count def current_auth_app_count current_user.auth_app_configurations.count end + + def analytics_properties + { + in_multi_mfa_selection_flow: in_multi_mfa_selection_flow?, + pii_like_keypaths: [[:mfa_method_counts, :phone]], + } + end end end diff --git a/app/controllers/users/webauthn_setup_controller.rb b/app/controllers/users/webauthn_setup_controller.rb index 0ad642cda6a..b3771332ea7 100644 --- a/app/controllers/users/webauthn_setup_controller.rb +++ b/app/controllers/users/webauthn_setup_controller.rb @@ -39,7 +39,8 @@ def confirm remember_device_default: remember_device_default, platform_authenticator: @platform_authenticator, ) - analytics.multi_factor_auth_setup(**result.to_h) + properties = result.to_h.merge(analytics_properties) + analytics.multi_factor_auth_setup(**properties) if result.success? process_valid_webauthn(form) else @@ -135,7 +136,7 @@ def process_valid_webauthn(form) platform_authenticator: form.platform_authenticator?, enabled_mfa_methods_count: mfa_user.enabled_mfa_methods_count, ) - Funnel::Registration::AddMfa.call(current_user.id, 'webauthn') + Funnel::Registration::AddMfa.call(current_user.id, 'webauthn', analytics) mark_user_as_fully_authenticated handle_remember_device if form.platform_authenticator? @@ -147,6 +148,12 @@ def process_valid_webauthn(form) redirect_to next_setup_path || after_mfa_setup_path end + def analytics_properties + { + in_multi_mfa_selection_flow: in_multi_mfa_selection_flow?, + } + end + def handle_remember_device save_user_opted_remember_device_pref save_remember_device_preference diff --git a/app/forms/totp_setup_form.rb b/app/forms/totp_setup_form.rb index fc024a9062e..5974b9fea06 100644 --- a/app/forms/totp_setup_form.rb +++ b/app/forms/totp_setup_form.rb @@ -42,14 +42,23 @@ def process_valid_submission user.save! end + def mfa_context + user + end + def extra_analytics_attributes { totp_secret_present: secret.present?, multi_factor_auth_method: 'totp', auth_app_configuration_id: @auth_app_config&.id, + enabled_mfa_methods_count: mfa_user.enabled_mfa_methods_count, } end + def mfa_user + MfaContext.new(user) + end + def create_auth_app(user, secret, new_timestamp, name) @auth_app_config = Db::AuthAppConfiguration.create(user, secret, new_timestamp, name) end diff --git a/app/forms/two_factor_options_form.rb b/app/forms/two_factor_options_form.rb index c47da559bf5..9baa54d7536 100644 --- a/app/forms/two_factor_options_form.rb +++ b/app/forms/two_factor_options_form.rb @@ -35,6 +35,7 @@ def mfa_user def extra_analytics_attributes { selection: selection, + selected_mfa_count: selection.count, enabled_mfa_methods_count: mfa_user.enabled_mfa_methods_count, } end diff --git a/app/services/analytics_events.rb b/app/services/analytics_events.rb index 51bbd6a3caa..41af2dfc6be 100644 --- a/app/services/analytics_events.rb +++ b/app/services/analytics_events.rb @@ -1325,10 +1325,16 @@ def multi_factor_auth_max_sends # Tracks when a user sets up a multi factor auth method # @param [String] multi_factor_auth_method - def multi_factor_auth_setup(multi_factor_auth_method:, **extra) + # @param [Boolean] in_multi_mfa_selection_flow + # @param [integer] enabled_mfa_methods_count + def multi_factor_auth_setup(multi_factor_auth_method:, + enabled_mfa_methods_count:, in_multi_mfa_selection_flow:, + **extra) track_event( 'Multi-Factor Authentication Setup', multi_factor_auth_method: multi_factor_auth_method, + in_multi_mfa_selection_flow: in_multi_mfa_selection_flow, + enabled_mfa_methods_count: enabled_mfa_methods_count, **extra, ) end @@ -2094,11 +2100,13 @@ def user_registration_2fa_additional_setup_visit # @param [Boolean] success # @param [Hash] errors # @param [Integer] enabled_mfa_methods_count + # @param [Integer] selected_mfa_count # @param ['voice', 'auth_app'] selection # Tracks when the the user has selected and submitted MFA auth methods on user registration def user_registration_2fa_setup( success:, errors: nil, + selected_mfa_count: nil, enabled_mfa_methods_count: nil, selection: nil, **extra @@ -2108,6 +2116,7 @@ def user_registration_2fa_setup( { success: success, errors: errors, + selected_mfa_count: selected_mfa_count, enabled_mfa_methods_count: enabled_mfa_methods_count, selection: selection, **extra, @@ -2115,6 +2124,21 @@ def user_registration_2fa_setup( ) end + # @param [String] mfa_method + # Tracks when the the user fully registered by submitting their first MFA method into the system + def user_registration_user_fully_registered( + mfa_method:, + **extra + ) + track_event( + 'User Registration: User Fully Registered', + { + mfa_method: mfa_method, + **extra, + }.compact, + ) + end + # @param [Boolean] success # @param [Hash] mfa_method_counts # @param [Integer] enabled_mfa_methods_count diff --git a/app/services/funnel/registration/add_mfa.rb b/app/services/funnel/registration/add_mfa.rb index 5dbfdea8b8d..8246c52e636 100644 --- a/app/services/funnel/registration/add_mfa.rb +++ b/app/services/funnel/registration/add_mfa.rb @@ -1,22 +1,23 @@ module Funnel module Registration class AddMfa - def self.call(user_id, mfa_method) + def self.call(user_id, mfa_method, analytics) now = Time.zone.now funnel = RegistrationLog.find_by(user_id: user_id) return if funnel.blank? || funnel.second_mfa.present? - params = if funnel.first_mfa.present? - { - second_mfa: mfa_method, - } - else - { - first_mfa: mfa_method, - first_mfa_at: now, - registered_at: now, - } - end + if funnel.first_mfa.present? + params = { + second_mfa: mfa_method, + } + else + params = { + first_mfa: mfa_method, + first_mfa_at: now, + registered_at: now, + } + analytics.user_registration_user_fully_registered(mfa_method: mfa_method) + end funnel.update!(params) end diff --git a/spec/controllers/two_factor_authentication/otp_verification_controller_spec.rb b/spec/controllers/two_factor_authentication/otp_verification_controller_spec.rb index a1b8c2e1308..5e796cd5155 100644 --- a/spec/controllers/two_factor_authentication/otp_verification_controller_spec.rb +++ b/spec/controllers/two_factor_authentication/otp_verification_controller_spec.rb @@ -56,6 +56,8 @@ area_code: parsed_phone.area_code, country_code: parsed_phone.country, phone_fingerprint: Pii::Fingerprinter.fingerprint(parsed_phone.e164), + enabled_mfa_methods_count: 1, + in_multi_mfa_selection_flow: false, } expect(@analytics).to receive(:track_event). @@ -102,6 +104,8 @@ area_code: parsed_phone.area_code, country_code: parsed_phone.country, phone_fingerprint: Pii::Fingerprinter.fingerprint(parsed_phone.e164), + enabled_mfa_methods_count: 1, + in_multi_mfa_selection_flow: false, } stub_analytics expect(@analytics).to receive(:track_mfa_submit_event). @@ -151,6 +155,8 @@ area_code: parsed_phone.area_code, country_code: parsed_phone.country, phone_fingerprint: Pii::Fingerprinter.fingerprint(parsed_phone.e164), + enabled_mfa_methods_count: 1, + in_multi_mfa_selection_flow: false, } stub_analytics @@ -206,6 +212,8 @@ area_code: parsed_phone.area_code, country_code: parsed_phone.country, phone_fingerprint: Pii::Fingerprinter.fingerprint(parsed_phone.e164), + enabled_mfa_methods_count: 1, + in_multi_mfa_selection_flow: false, } stub_analytics @@ -334,6 +342,8 @@ area_code: parsed_phone.area_code, country_code: parsed_phone.country, phone_fingerprint: Pii::Fingerprinter.fingerprint(parsed_phone.e164), + enabled_mfa_methods_count: 1, + in_multi_mfa_selection_flow: false, } expect(@analytics).to receive(:track_event). @@ -400,6 +410,8 @@ area_code: parsed_phone.area_code, country_code: parsed_phone.country, phone_fingerprint: Pii::Fingerprinter.fingerprint(parsed_phone.e164), + enabled_mfa_methods_count: 1, + in_multi_mfa_selection_flow: false, } expect(@analytics).to have_received(:track_event). @@ -448,6 +460,8 @@ area_code: parsed_phone.area_code, country_code: parsed_phone.country, phone_fingerprint: Pii::Fingerprinter.fingerprint(parsed_phone.e164), + enabled_mfa_methods_count: 0, + in_multi_mfa_selection_flow: false, } expect(@analytics).to have_received(:track_event). diff --git a/spec/controllers/users/totp_setup_controller_spec.rb b/spec/controllers/users/totp_setup_controller_spec.rb index cc4095b742c..3c68d10f6a2 100644 --- a/spec/controllers/users/totp_setup_controller_spec.rb +++ b/spec/controllers/users/totp_setup_controller_spec.rb @@ -108,6 +108,9 @@ totp_secret_present: true, multi_factor_auth_method: 'totp', auth_app_configuration_id: nil, + enabled_mfa_methods_count: 0, + in_multi_mfa_selection_flow: false, + pii_like_keypaths: [[:mfa_method_counts, :phone]], } expect(@analytics).to have_received(:track_event). @@ -137,6 +140,9 @@ totp_secret_present: true, multi_factor_auth_method: 'totp', auth_app_configuration_id: next_auth_app_id, + enabled_mfa_methods_count: 2, + in_multi_mfa_selection_flow: false, + pii_like_keypaths: [[:mfa_method_counts, :phone]], } expect(@analytics).to have_received(:track_event). @@ -167,6 +173,9 @@ totp_secret_present: true, multi_factor_auth_method: 'totp', auth_app_configuration_id: nil, + enabled_mfa_methods_count: 1, + in_multi_mfa_selection_flow: false, + pii_like_keypaths: [[:mfa_method_counts, :phone]], } expect(@analytics).to have_received(:track_event). @@ -198,6 +207,9 @@ totp_secret_present: true, multi_factor_auth_method: 'totp', auth_app_configuration_id: nil, + enabled_mfa_methods_count: 1, + in_multi_mfa_selection_flow: false, + pii_like_keypaths: [[:mfa_method_counts, :phone]], } expect(@analytics).to have_received(:track_event). @@ -228,6 +240,9 @@ totp_secret_present: true, multi_factor_auth_method: 'totp', auth_app_configuration_id: nil, + enabled_mfa_methods_count: 0, + in_multi_mfa_selection_flow: false, + pii_like_keypaths: [[:mfa_method_counts, :phone]], } expect(@analytics).to have_received(:track_event). with('Multi-Factor Authentication Setup', result) @@ -259,6 +274,9 @@ totp_secret_present: true, multi_factor_auth_method: 'totp', auth_app_configuration_id: next_auth_app_id, + enabled_mfa_methods_count: 1, + in_multi_mfa_selection_flow: true, + pii_like_keypaths: [[:mfa_method_counts, :phone]], } expect(@analytics).to have_received(:track_event). @@ -269,7 +287,7 @@ context 'when user has multiple MFA methods left in user session' do let(:mfa_selections) { ['auth_app', 'voice'] } - it 'redirects to mfa confirmation path with a success message and still logs analytics' do + it 'redirects to next mfa path with a success message and still logs analytics' do expect(response).to redirect_to(phone_setup_url) result = { @@ -278,6 +296,9 @@ totp_secret_present: true, multi_factor_auth_method: 'totp', auth_app_configuration_id: next_auth_app_id, + enabled_mfa_methods_count: 1, + in_multi_mfa_selection_flow: true, + pii_like_keypaths: [[:mfa_method_counts, :phone]], } expect(@analytics).to have_received(:track_event). @@ -306,6 +327,9 @@ totp_secret_present: false, multi_factor_auth_method: 'totp', auth_app_configuration_id: nil, + enabled_mfa_methods_count: 0, + in_multi_mfa_selection_flow: false, + pii_like_keypaths: [[:mfa_method_counts, :phone]], } expect(@analytics).to have_received(:track_event). diff --git a/spec/controllers/users/two_factor_authentication_setup_controller_spec.rb b/spec/controllers/users/two_factor_authentication_setup_controller_spec.rb index f66ae7a4436..47a8e893593 100644 --- a/spec/controllers/users/two_factor_authentication_setup_controller_spec.rb +++ b/spec/controllers/users/two_factor_authentication_setup_controller_spec.rb @@ -87,6 +87,7 @@ enabled_mfa_methods_count: 0, selection: ['voice', 'auth_app'], success: true, + selected_mfa_count: 2, errors: {}, } diff --git a/spec/controllers/users/webauthn_setup_controller_spec.rb b/spec/controllers/users/webauthn_setup_controller_spec.rb index 662955546e5..a33a5545666 100644 --- a/spec/controllers/users/webauthn_setup_controller_spec.rb +++ b/spec/controllers/users/webauthn_setup_controller_spec.rb @@ -81,6 +81,7 @@ multi_factor_auth_method: 'webauthn', success: true, errors: {}, + in_multi_mfa_selection_flow: false, pii_like_keypaths: [[:mfa_method_counts, :phone]], } expect(@analytics).to receive(:track_event). diff --git a/spec/forms/totp_setup_form_spec.rb b/spec/forms/totp_setup_form_spec.rb index ec01fd29ee4..a7d0bdc78fe 100644 --- a/spec/forms/totp_setup_form_spec.rb +++ b/spec/forms/totp_setup_form_spec.rb @@ -14,6 +14,7 @@ totp_secret_present: true, multi_factor_auth_method: 'totp', auth_app_configuration_id: next_auth_app_id, + enabled_mfa_methods_count: 1, } expect(form.submit.to_h).to eq( diff --git a/spec/services/funnel/registration/add_mfa_spec.rb b/spec/services/funnel/registration/add_mfa_spec.rb index a31f79a13d7..375a3a596c0 100644 --- a/spec/services/funnel/registration/add_mfa_spec.rb +++ b/spec/services/funnel/registration/add_mfa_spec.rb @@ -1,6 +1,7 @@ require 'rails_helper' describe Funnel::Registration::AddMfa do + let(:analytics) { FakeAnalytics.new } subject { described_class } let(:user_id) do @@ -12,15 +13,15 @@ let(:funnel) { RegistrationLog.all.first } it 'adds an 1st mfa' do - subject.call(user_id, 'phone') + subject.call(user_id, 'phone', analytics) expect(funnel.first_mfa).to eq('phone') expect(funnel.first_mfa_at).to be_present end it 'adds a 2nd mfa' do - subject.call(user_id, 'phone') - subject.call(user_id, 'backup_codes') + subject.call(user_id, 'phone', analytics) + subject.call(user_id, 'backup_codes', analytics) expect(funnel.first_mfa).to eq('phone') expect(funnel.first_mfa_at).to be_present @@ -28,9 +29,9 @@ end it 'does not add a 3rd mfa' do - subject.call(user_id, 'phone') - subject.call(user_id, 'backup_codes') - subject.call(user_id, 'auth_app') + subject.call(user_id, 'phone', analytics) + subject.call(user_id, 'backup_codes', analytics) + subject.call(user_id, 'auth_app', analytics) expect(funnel.first_mfa).to eq('phone') expect(funnel.second_mfa).to eq('backup_codes') diff --git a/spec/services/funnel/registration/range_registered_count_spec.rb b/spec/services/funnel/registration/range_registered_count_spec.rb index eaf520bf821..259f473a8ed 100644 --- a/spec/services/funnel/registration/range_registered_count_spec.rb +++ b/spec/services/funnel/registration/range_registered_count_spec.rb @@ -1,6 +1,7 @@ require 'rails_helper' describe Funnel::Registration::RangeRegisteredCount do + let(:analytics) { FakeAnalytics.new } subject { described_class } let(:start) { '2019-01-01 00:00:00' } @@ -53,7 +54,7 @@ def register_user(year, month, day) user_id = user.id Funnel::Registration::Create.call(user_id) Funnel::Registration::AddPassword.call(user_id) - Funnel::Registration::AddMfa.call(user_id, 'backup_codes') + Funnel::Registration::AddMfa.call(user_id, 'backup_codes', analytics) end end end diff --git a/spec/services/funnel/registration/total_registered_count_spec.rb b/spec/services/funnel/registration/total_registered_count_spec.rb index 0af532d6791..03641f68a88 100644 --- a/spec/services/funnel/registration/total_registered_count_spec.rb +++ b/spec/services/funnel/registration/total_registered_count_spec.rb @@ -1,6 +1,7 @@ require 'rails_helper' describe Funnel::Registration::TotalRegisteredCount do + let(:analytics) { FakeAnalytics.new } subject { described_class } it 'returns 0' do @@ -18,7 +19,7 @@ expect(Funnel::Registration::TotalRegisteredCount.call).to eq(0) - Funnel::Registration::AddMfa.call(user_id, 'phone') + Funnel::Registration::AddMfa.call(user_id, 'phone', analytics) expect(Funnel::Registration::TotalRegisteredCount.call).to eq(1) end @@ -41,6 +42,6 @@ def register_user user_id = user.id Funnel::Registration::Create.call(user_id) Funnel::Registration::AddPassword.call(user_id) - Funnel::Registration::AddMfa.call(user_id, 'backup_codes') + Funnel::Registration::AddMfa.call(user_id, 'backup_codes', analytics) end end