diff --git a/core/modules/basic_auth/basic_auth.services.yml b/core/modules/basic_auth/basic_auth.services.yml
index 13a6cb15b90b8b7691f0b970d3870d52e3436207..4c7a4493d2a937f15db78b381f85aa8bdce08fee 100644
--- a/core/modules/basic_auth/basic_auth.services.yml
+++ b/core/modules/basic_auth/basic_auth.services.yml
@@ -1,6 +1,6 @@
 services:
   authentication.basic_auth:
     class: Drupal\basic_auth\Authentication\Provider\BasicAuth
-    arguments: ['@config.factory']
+    arguments: ['@config.factory', '@user.auth']
     tags:
       - { name: authentication_provider, priority: 100 }
diff --git a/core/modules/basic_auth/lib/Drupal/basic_auth/Authentication/Provider/BasicAuth.php b/core/modules/basic_auth/lib/Drupal/basic_auth/Authentication/Provider/BasicAuth.php
index 282b89102dcd2fe077fa9ad08b6bbcd071c57623..579d8a0236f1e363da37d6c55b1e130572aea913 100644
--- a/core/modules/basic_auth/lib/Drupal/basic_auth/Authentication/Provider/BasicAuth.php
+++ b/core/modules/basic_auth/lib/Drupal/basic_auth/Authentication/Provider/BasicAuth.php
@@ -11,6 +11,7 @@
 use Drupal\Core\Authentication\AuthenticationProviderInterface;
 use Drupal\Core\Config\Config;
 use Drupal\Core\Config\ConfigFactoryInterface;
+use Drupal\user\UserAuthInterface;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
 use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
@@ -28,14 +29,22 @@ class BasicAuth implements AuthenticationProviderInterface {
    */
   protected $configFactory;
 
+  /**
+   * The user auth service.
+   *
+   * @var \Drupal\user\UserAuthInterface
+   */
+  protected $userAuth;
+
   /**
    * Constructs a HTTP basic authentication provider object.
    *
    * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
    *   The config factory.
    */
-  public function __construct(ConfigFactoryInterface $config_factory) {
+  public function __construct(ConfigFactoryInterface $config_factory, UserAuthInterface $user_auth) {
     $this->configFactory = $config_factory;
+    $this->userAuth = $user_auth;
   }
 
   /**
@@ -53,7 +62,7 @@ public function applies(Request $request) {
   public function authenticate(Request $request) {
     $username = $request->headers->get('PHP_AUTH_USER');
     $password = $request->headers->get('PHP_AUTH_PW');
-    $uid = user_authenticate($username, $password);
+    $uid = $this->userAuth->authenticate($username, $password);
     if ($uid) {
       return user_load($uid);
     }
diff --git a/core/modules/user/lib/Drupal/user/Form/UserLoginForm.php b/core/modules/user/lib/Drupal/user/Form/UserLoginForm.php
index 46744a4dbbddd4fcdb8efcfb4335fa5f4e493a5b..dcc6845d5cb2a778793f4ff7c83abb2a1f1ab260 100644
--- a/core/modules/user/lib/Drupal/user/Form/UserLoginForm.php
+++ b/core/modules/user/lib/Drupal/user/Form/UserLoginForm.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Flood\FloodInterface;
 use Drupal\Core\Form\FormBase;
+use Drupal\user\UserAuthInterface;
 use Drupal\user\UserStorageControllerInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -31,6 +32,13 @@ class UserLoginForm extends FormBase {
    */
   protected $userStorage;
 
+  /**
+   * The user authentication object.
+   *
+   * @var \Drupal\user\UserAuthInterface
+   */
+  protected $userAuth;
+
   /**
    * Constructs a new UserLoginForm.
    *
@@ -38,10 +46,13 @@ class UserLoginForm extends FormBase {
    *   The flood service.
    * @param \Drupal\user\UserStorageControllerInterface $user_storage
    *   The user storage controller.
+   * @param \Drupal\user\UserAuthInterface $user_auth
+   *   The user authentication object.
    */
-  public function __construct(FloodInterface $flood, UserStorageControllerInterface $user_storage) {
+  public function __construct(FloodInterface $flood, UserStorageControllerInterface $user_storage, UserAuthInterface $user_auth) {
     $this->flood = $flood;
     $this->userStorage = $user_storage;
+    $this->userAuth = $user_auth;
   }
 
   /**
@@ -50,7 +61,8 @@ public function __construct(FloodInterface $flood, UserStorageControllerInterfac
   public static function create(ContainerInterface $container) {
     return new static(
       $container->get('flood'),
-      $container->get('entity.manager')->getStorageController('user')
+      $container->get('entity.manager')->getStorageController('user'),
+      $container->get('user.auth')
     );
   }
 
@@ -165,7 +177,7 @@ public function validateAuthentication(array &$form, array &$form_state) {
       }
       // We are not limited by flood control, so try to authenticate.
       // Set $form_state['uid'] as a flag for self::validateFinal().
-      $form_state['uid'] = user_authenticate($form_state['values']['name'], $password);
+      $form_state['uid'] = $this->userAuth->authenticate($form_state['values']['name'], $password);
     }
   }
 
diff --git a/core/modules/user/lib/Drupal/user/UserAuth.php b/core/modules/user/lib/Drupal/user/UserAuth.php
new file mode 100644
index 0000000000000000000000000000000000000000..3ce2683a4387d7d737b26db24ea34287cc6846c5
--- /dev/null
+++ b/core/modules/user/lib/Drupal/user/UserAuth.php
@@ -0,0 +1,72 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\user\UserAuth.
+ */
+
+namespace Drupal\user;
+
+use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Entity\EntityStorageControllerInterface;
+use Drupal\Core\Password\PasswordInterface;
+
+/**
+ * Validates user authentication credentials.
+ */
+class UserAuth implements UserAuthInterface {
+
+  /**
+   * The user storage.
+   *
+   * @var \Drupal\Core\Entity\EntityStorageControllerInterface
+   */
+  protected $storage;
+
+  /**
+   * The password service.
+   *
+   * @var \Drupal\Core\Password\PasswordInterface
+   */
+  protected $passwordChecker;
+
+  /**
+   * Constructs a UserAuth object.
+   *
+   * @param \Drupal\Core\Entity\EntityStorageControllerInterface $storage
+   *   The user storage.
+   * @param \Drupal\Core\Password\PasswordInterface $password_checker
+   *   The password service.
+   */
+  public function __construct(EntityManagerInterface $entity_manager, PasswordInterface $password_checker) {
+    $this->storage = $entity_manager->getStorageController('user');
+    $this->passwordChecker = $password_checker;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function authenticate($username, $password) {
+    $uid = FALSE;
+
+    if (!empty($username) && !empty($password)) {
+      $account_search = $this->storage->loadByProperties(array('name' => $username));
+
+      if ($account = reset($account_search)) {
+        if ($this->passwordChecker->check($password, $account)) {
+          // Successful authentication.
+          $uid = $account->id();
+
+          // Update user to new password scheme if needed.
+          if ($this->passwordChecker->userNeedsNewHash($account)) {
+            $account->setPassword($password);
+            $account->save();
+          }
+        }
+      }
+    }
+
+    return $uid;
+  }
+
+}
diff --git a/core/modules/user/lib/Drupal/user/UserAuthInterface.php b/core/modules/user/lib/Drupal/user/UserAuthInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..1044ec18e9507b4a89b9303d4b11da3ae0f1fb6f
--- /dev/null
+++ b/core/modules/user/lib/Drupal/user/UserAuthInterface.php
@@ -0,0 +1,27 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\user\UserAuthInterface.
+ */
+
+namespace Drupal\user;
+
+/**
+ * An interface for validating user authentication credentials.
+ */
+interface UserAuthInterface {
+
+  /**
+   * Validates user authentication credentials.
+   *
+   * @param string $username
+   *   The user name to authenticate.
+   * @param string $password
+   *   A plain-text password, such as trimmed text from form values.
+   * @return int|bool
+   *   The user's uid on success, or FALSE on failure to authenticate.
+   */
+  public function authenticate($username, $password);
+
+}
diff --git a/core/modules/user/tests/Drupal/user/Tests/UserAuthTest.php b/core/modules/user/tests/Drupal/user/Tests/UserAuthTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..c658e608f7d90d4ed4700137f23bf1f19744e1e0
--- /dev/null
+++ b/core/modules/user/tests/Drupal/user/Tests/UserAuthTest.php
@@ -0,0 +1,215 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\user\Tests\UserAuthTest.
+ */
+
+namespace Drupal\user\Tests;
+
+use Drupal\Tests\UnitTestCase;
+use Drupal\user\UserAuth;
+
+/**
+ * Tests the UserAuth class.
+ *
+ * @group Drupal
+ * @group User
+ *
+ * @coverDefaultClass \Drupal\user\UserAuth
+ */
+class UserAuthTest extends UnitTestCase {
+
+  /**
+   * The mock user storage controller.
+   *
+   * @var \Drupal\Core\Entity\EntityStorageControllerInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $userStorage;
+
+  /**
+   * The mocked password service.
+   *
+   * @var \Drupal\Core\Password\PasswordInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $passwordService;
+
+  /**
+   * The mock user.
+   *
+   * @var \Drupal\user\Entity\User|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $testUser;
+
+  /**
+   * The user auth object under test.
+   *
+   * @var \Drupal\user\UserAuth
+   */
+  protected $userAuth;
+
+  /**
+   * The test username.
+   *
+   * @var string
+   */
+  protected $username = 'test_user';
+
+  /**
+   * The test password
+   *
+   * @var string
+   */
+  protected $password = 'password';
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'User auth service',
+      'description' => 'Tests the user auth service',
+      'group' => 'User',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp() {
+    $this->userStorage = $this->getMock('Drupal\Core\Entity\EntityStorageControllerInterface');
+
+    $entity_manager = $this->getMock('Drupal\Core\Entity\EntityManagerInterface');
+    // Getting the user storage controller should only happen once per test.
+    $entity_manager->expects($this->once())
+      ->method('getStorageController')
+      ->with('user')
+      ->will($this->returnValue($this->userStorage));
+
+    $this->passwordService = $this->getMock('Drupal\Core\Password\PasswordInterface');
+
+    $this->testUser = $this->getMockBuilder('Drupal\user\Entity\User')
+      ->disableOriginalConstructor()
+      ->setMethods(array('id', 'setPassword', 'save'))
+      ->getMock();
+
+    $this->userAuth = new UserAuth($entity_manager, $this->passwordService);
+  }
+
+  /**
+   * Tests failing authentication with missing credential parameters.
+   *
+   * @covers ::authenticate()
+   *
+   * @dataProvider providerTestAuthenticateWithMissingCredentials
+   */
+  public function testAuthenticateWithMissingCredentials($username, $password) {
+    $this->userStorage->expects($this->never())
+      ->method('loadByProperties');
+
+    $this->assertFalse($this->userAuth->authenticate($username, $password));
+  }
+
+  /**
+   * Data provider for testAuthenticateWithMissingCredentials().
+   *
+   * @return array
+   */
+  public function providerTestAuthenticateWithMissingCredentials() {
+    return array(
+      array(NULL, NULL),
+      array(NULL, ''),
+      array('', NULL),
+      array('', ''),
+    );
+  }
+
+  /**
+   * Tests the authenticate method with no account returned.
+   *
+   * @covers ::authenticate()
+   */
+  public function testAuthenticateWithNoAccountReturned() {
+    $this->userStorage->expects($this->once())
+      ->method('loadByProperties')
+      ->with(array('name' => $this->username))
+      ->will($this->returnValue(array()));
+
+    $this->assertFalse($this->userAuth->authenticate($this->username, $this->password));
+  }
+
+  /**
+   * Tests the authenticate method with an incorrect password.
+   *
+   * @covers ::authenticate()
+   */
+  public function testAuthenticateWithIncorrectPassword() {
+    $this->userStorage->expects($this->once())
+      ->method('loadByProperties')
+      ->with(array('name' => $this->username))
+      ->will($this->returnValue(array($this->testUser)));
+
+    $this->passwordService->expects($this->once())
+      ->method('check')
+      ->with($this->password, $this->testUser)
+      ->will($this->returnValue(FALSE));
+
+    $this->assertFalse($this->userAuth->authenticate($this->username, $this->password));
+  }
+
+  /**
+   * Tests the authenticate method with a correct password.
+   *
+   * @covers ::authenticate()
+   */
+  public function testAuthenticateWithCorrectPassword() {
+    $this->testUser->expects($this->once())
+      ->method('id')
+      ->will($this->returnValue(1));
+
+    $this->userStorage->expects($this->once())
+      ->method('loadByProperties')
+      ->with(array('name' => $this->username))
+      ->will($this->returnValue(array($this->testUser)));
+
+    $this->passwordService->expects($this->once())
+      ->method('check')
+      ->with($this->password, $this->testUser)
+      ->will($this->returnValue(TRUE));
+
+    $this->assertsame(1, $this->userAuth->authenticate($this->username, $this->password));
+  }
+
+  /**
+   * Tests the authenticate method with a correct password and new password hash.
+   *
+   * @covers ::authenticate()
+   */
+  public function testAuthenticateWithCorrectPasswordAndNewPasswordHash() {
+    $this->testUser->expects($this->once())
+      ->method('id')
+      ->will($this->returnValue(1));
+    $this->testUser->expects($this->once())
+      ->method('setPassword')
+      ->with($this->password);
+    $this->testUser->expects($this->once())
+      ->method('save');
+
+    $this->userStorage->expects($this->once())
+      ->method('loadByProperties')
+      ->with(array('name' => $this->username))
+      ->will($this->returnValue(array($this->testUser)));
+
+    $this->passwordService->expects($this->once())
+      ->method('check')
+      ->with($this->password, $this->testUser)
+      ->will($this->returnValue(TRUE));
+    $this->passwordService->expects($this->once())
+      ->method('userNeedsNewHash')
+      ->with($this->testUser)
+      ->will($this->returnValue(TRUE));
+
+    $this->assertsame(1, $this->userAuth->authenticate($this->username, $this->password));
+  }
+
+}
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index 8c83ae591007250b8ee19af3595c95a9b3d0bf2f..ab9a163e86572174067ce2cca49d4f80321275ac 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -796,26 +796,12 @@ function user_admin_paths() {
  *   A plain-text password, such as trimmed text from form values.
  * @return
  *   The user's uid on success, or FALSE on failure to authenticate.
+ *
+ * @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
+ *   Use \Drupal\user\UserAuth::authenticate() instead.
  */
 function user_authenticate($name, $password) {
-  $uid = FALSE;
-  if (!empty($name) && !empty($password)) {
-    $account = user_load_by_name($name);
-    if ($account) {
-      $password_hasher = \Drupal::service('password');
-      if ($password_hasher->check($password, $account)) {
-        // Successful authentication.
-        $uid = $account->id();
-
-        // Update user to new password scheme if needed.
-        if ($password_hasher->userNeedsNewHash($account)) {
-          $account->setPassword($password);
-          $account->save();
-        }
-      }
-    }
-  }
-  return $uid;
+  return \Drupal::service('user.auth')->authenticate($name, $password);
 }
 
 /**
diff --git a/core/modules/user/user.services.yml b/core/modules/user/user.services.yml
index 23d870699f359788a03fe8f78a8cb0e121bf400a..36d1e79a6e528af2f7adbdf12c8ba6e17364209d 100644
--- a/core/modules/user/user.services.yml
+++ b/core/modules/user/user.services.yml
@@ -33,3 +33,6 @@ services:
   user.permissions_hash:
     class: Drupal\user\PermissionsHash
     arguments: ['@private_key', '@cache.cache']
+  user.auth:
+    class: Drupal\user\UserAuth
+    arguments: ['@entity.manager', '@password']