diff --git a/app/controllers/concerns/authenticates_with_two_factor.rb b/app/controllers/concerns/authenticates_with_two_factor.rb
new file mode 100644
index 0000000000000000000000000000000000000000..d5918a7af3b02b214d443f692da0748a3fcc440f
--- /dev/null
+++ b/app/controllers/concerns/authenticates_with_two_factor.rb
@@ -0,0 +1,30 @@
+# == AuthenticatesWithTwoFactor
+#
+# Controller concern to handle two-factor authentication
+#
+# Upon inclusion, skips `require_no_authentication` on `:create`.
+module AuthenticatesWithTwoFactor
+  extend ActiveSupport::Concern
+
+  included do
+    # This action comes from DeviseController, but because we call `sign_in`
+    # manually, not skipping this action would cause a "You are already signed
+    # in." error message to be shown upon successful login.
+    skip_before_action :require_no_authentication, only: [:create]
+  end
+
+  # Store the user's ID in the session for later retrieval and render the
+  # two factor code prompt
+  #
+  # The user must have been authenticated with a valid login and password
+  # before calling this method!
+  #
+  # user - User record
+  #
+  # Returns nil
+  def prompt_for_two_factor(user)
+    session[:otp_user_id] = user.id
+
+    render 'devise/sessions/two_factor' and return
+  end
+end
diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb
index d4ff0d975616ee89033c94bc0ece017f8998a960..b89b4c2735053cfa9632c55ac214e5f412441545 100644
--- a/app/controllers/sessions_controller.rb
+++ b/app/controllers/sessions_controller.rb
@@ -1,11 +1,7 @@
 class SessionsController < Devise::SessionsController
-  prepend_before_action :authenticate_with_two_factor, only: [:create]
+  include AuthenticatesWithTwoFactor
 
-  # This action comes from DeviseController, but because we call `sign_in`
-  # manually inside `authenticate_with_two_factor`, not skipping this action
-  # would cause a "You are already signed in." error message to be shown upon
-  # successful login.
-  skip_before_action :require_no_authentication, only: [:create]
+  prepend_before_action :authenticate_with_two_factor, only: [:create]
 
   def new
     redirect_path =
@@ -74,9 +70,7 @@ class SessionsController < Devise::SessionsController
       end
     else
       if user && user.valid_password?(user_params[:password])
-        # Save the user's ID to session so we can ask for a one-time password
-        session[:otp_user_id] = user.id
-        render :two_factor and return
+        prompt_for_two_factor(user)
       end
     end
   end