diff --git a/lib/Drupal/masquerade/Form/MasqueradeBlockForm.php b/lib/Drupal/masquerade/Form/MasqueradeBlockForm.php
new file mode 100644
index 0000000..9b94c5b
--- /dev/null
+++ b/lib/Drupal/masquerade/Form/MasqueradeBlockForm.php
@@ -0,0 +1,90 @@
+<?php
+
+namespace Drupal\masquerade\Form;
+
+use Drupal\Core\Controller\ControllerInterface;
+use Drupal\Core\Form\FormInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+class MasqueradeBlockForm implements ControllerInterface, FormInterface {
+
+  protected $database;
+
+  /**
+   * This method lets us inject the services this class needs.
+   *
+   * Only inject services that are actually needed. Which services
+   * are needed will vary by the controller.
+   */
+  public static function create(ContainerInterface $container) {
+
+    return new static($container);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function __construct(Connection $database) {
+    $this->database = $database;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getFormID() {
+    return 'masquerade_block';
+  }
+
+  /**
+   * Form constructor for the Masquerade block form.
+   */
+  public function buildForm(array $form, array &$form_state) {
+    $form['autocomplete'] = array(
+      '#type' => 'container',
+      '#attributes' => array('class' => array('container-inline')),
+    );
+    $form['autocomplete']['masquerade_as'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Username'),
+      '#title_display' => 'invisible',
+      '#required' => TRUE,
+      '#placeholder' => t('Masquerade asтАж'),
+      '#size' => '18',
+      '#autocomplete_path' => 'masquerade/autocomplete',
+    );
+    $form['autocomplete']['actions'] = array('#type' => 'actions');
+    $form['autocomplete']['actions']['submit'] = array(
+      '#type' => 'submit',
+      '#value' => t('Switch'),
+    );
+
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function validateForm(array &$form, array &$form_state) {
+    $name = $form_state['values']['masquerade_as'];
+    // @todo Use entity_load_multiple_by_properties('user') to skip blocked users.
+    if (!$target_account = user_load_by_name($name)) {
+      form_set_error('masquerade_as', t('The username %target_user does not exist. Please enter a valid username.', array(
+        '%target_user' => $name,
+      )));
+      return;
+    }
+    elseif ($error = masquerade_switch_user_validate($target_account)) {
+      form_set_error('masquerade_as', $error);
+    }
+    else {
+      $form_state['masquerade_target_account'] = $target_account;
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submitForm(array &$form, array &$form_state) {
+    masquerade_switch_user($form_state['masquerade_target_account']);
+  }
+}
diff --git a/masquerade.module b/masquerade.module
index 213d928..1c29dc4 100644
--- a/masquerade.module
+++ b/masquerade.module
@@ -6,6 +6,7 @@
  */
 
 use Drupal\user\Plugin\Core\Entity\User;
+use Drupal\Core\Form\FormInterface;
 use Symfony\Component\HttpFoundation\JsonResponse;
 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
@@ -63,12 +64,9 @@ function masquerade_permission() {
  * Implements hook_menu().
  */
 function masquerade_menu() {
-  // @todo rebuild on top of FormInterface.
   $items['masquerade'] = array(
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('masquerade_block_form'),
-    'access arguments' => array('masquerade'),
-    'type' => MENU_CALLBACK,
+    'title' => 'Masquerade',
+    'route_name' => 'masquerade',
   );
   // @todo http://dgo.to/1798296 move this to route layer.
   $items['user/%user/masquerade'] = array(
@@ -130,7 +128,7 @@ function masquerade_user_access(User $target_account) {
 
   // Deny access if the current user is masquerading already or tries to
   // masquerade as himself.
-  if (isset($_SESSION['masquerading']) || $user->uid == $target_account->id()) {
+  if (isset($_SESSION['masquerading']) || $user->id() == $target_account->id()) {
     return FALSE;
   }
 
@@ -162,9 +160,9 @@ function masquerade_user_access(User $target_account) {
  * This default implementation only returns TRUE and never FALSE, since
  * alternative access implementations could not work otherwise.
  */
-function masquerade_masquerade_access($user, User $target_account) {
+function masquerade_masquerade_access(User $user, User $target_account) {
   // Uid 1 may masquerade as anyone.
-  if ($user->uid == 1) {
+  if ($user->id() == 1) {
     return TRUE;
   }
   // No one can masquerade as uid 1.
@@ -252,62 +250,12 @@ function masquerade_user_view(User $account, $display, $view_mode, $langcode) {
 }
 
 /**
- * Form constructor for the Masquerade block form.
- */
-function masquerade_block_form($form, &$form_state) {
-  $form['autocomplete'] = array(
-    '#type' => 'container',
-    '#attributes' => array('class' => array('container-inline')),
-  );
-  $form['autocomplete']['masquerade_as'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Username'),
-    '#title_display' => 'invisible',
-    '#required' => TRUE,
-    '#placeholder' => t('Masquerade asтАж'),
-    '#size' => '18',
-    '#autocomplete_path' => 'masquerade/autocomplete',
-  );
-  $form['autocomplete']['actions'] = array('#type' => 'actions');
-  $form['autocomplete']['actions']['submit'] = array(
-    '#type' => 'submit',
-    '#value' => t('Switch'),
-  );
-  return $form;
-}
-
-/**
- * Form validation handler for masquerade_block_form().
- */
-function masquerade_block_form_validate($form, &$form_state) {
-  $name = $form_state['values']['masquerade_as'];
-  // @todo Use entity_load_multiple_by_properties('user') to skip blocked users.
-  if (!$target_account = user_load_by_name($name)) {
-    form_set_error('masquerade_as', t('The username %target_user does not exist. Please enter a valid username.', array(
-      '%target_user' => $name,
-    )));
-    return;
-  }
-  elseif ($error = masquerade_switch_user_validate($target_account)) {
-    form_set_error('masquerade_as', $error);
-  }
-  else {
-    $form_state['masquerade_target_account'] = $target_account;
-  }
-}
-
-/**
- * Form submission handler for masquerade_block_form().
- */
-function masquerade_block_form_submit($form, &$form_state) {
-  masquerade_switch_user($form_state['masquerade_target_account']);
-}
-
-/**
  * Page callback; Masquerades as a given user.
  *
  * @param \Drupal\user\Plugin\Core\Entity\User $target_account
  *   The user account object to masquerade as.
+ *
+ * @throws Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
  */
 function masquerade_switch_user_page(User $target_account) {
   $token = Drupal::service('request')->query->get('token');
@@ -349,10 +297,10 @@ function masquerade_switch_user_validate(User $target_account) {
       )),
     ));
   }
-  if ($target_account->uid == $user->uid) {
+  if ($target_account->id() == $user->id()) {
     return t('You cannot masquerade as yourself. Please choose a different user to masquerade as.');
   }
-  if (config('system.maintenance')->get('enabled') && !user_access('access site in maintenance mode', $target_account)) {
+  if (Drupal::config('system.maintenance')->get('enabled') && !user_access('access site in maintenance mode', $target_account)) {
     return t('!user is not permitted to %permission. <a href="@maintenance-url">Disable maintenance mode</a> to masquerade as !user.', array(
       '!user' => theme('username', array('account' => $target_account)),
       '%permission' => t('Use the site in maintenance mode'),
@@ -382,7 +330,7 @@ function masquerade_switch_user(User $target_account) {
   Drupal::moduleHandler()->invokeAll('user_logout', array($user));
   drupal_session_regenerate();
 
-  $_SESSION['masquerading'] = $user->uid;
+  $_SESSION['masquerading'] = $user->id();
 
   watchdog('masquerade', 'User %username masqueraded as %target_username.', array(
     // Use "name" here because $user object could not be fully initialized.
@@ -394,7 +342,7 @@ function masquerade_switch_user(User $target_account) {
   )));
 
   $user = $target_account;
-  $user->masquerading = $target_account->uid;
+  $user->masquerading = $target_account->id();
 
   // Call all login hooks when switching to masquerading user.
   Drupal::moduleHandler()->invokeAll('user_login', array($user));
@@ -414,7 +362,10 @@ function masquerade_switch_back_page() {
     drupal_set_message(t('You are no longer masquerading as !user.', array(
       '!user' => theme('username', array('account' => $old_user)),
     )));
-    drupal_goto(Drupal::request()->server->get('HTTP_REFERER'));
+
+    $url = Drupal::request()->server->get('HTTP_REFERER');
+    $redirect = new \Symfony\Component\HttpFoundation\RedirectResponse(url($url, array('absolute' => true)));
+    $redirect->send();
   }
   else {
     throw new AccessDeniedHttpException();
@@ -464,7 +415,7 @@ function masquerade_form_user_admin_account_alter(&$form, &$form_state) {
     // @todo Core: The already loaded accounts are not provided.
     $account = user_load($uid);
     if (masquerade_user_access($account)) {
-      $path = 'user/' . $account->uid . '/masquerade';
+      $path = 'user/' . $account->id() . '/masquerade';
       $row['operations']['data']['#links']['masquerade'] = array(
         'title' => t('Masquerade'),
         'href' => $path,
diff --git a/masquerade.routing.yml b/masquerade.routing.yml
index 5721a37..29ac5ff 100644
--- a/masquerade.routing.yml
+++ b/masquerade.routing.yml
@@ -2,8 +2,15 @@
 # allowed to masquerade do not necessarily need to have access to view user
 # profiles.
 masquerade_autocomplete:
-  pattern: '/masquerade/autocomplete'
+  pattern: 'masquerade/autocomplete'
   defaults:
-    _controller: '\Drupal\user\UserAutocompleteController::autocompleteUser'
+    _controller: '\Drupal\user\Controller\UserAutocompleteController::autocompleteUser'
   requirements:
     _permission: 'masquerade'
+
+masquerade:
+  pattern: 'masquerade'
+  defaults:
+    _form: '\Drupal\masquerade\Form\MasqueradeBlockForm'
+  requirements:
+    _permission: 'masquerade'
\ No newline at end of file
