diff --git a/core/modules/rest/src/Plugin/ResourceBase.php b/core/modules/rest/src/Plugin/ResourceBase.php
index 46f77f6..240461f 100644
--- a/core/modules/rest/src/Plugin/ResourceBase.php
+++ b/core/modules/rest/src/Plugin/ResourceBase.php
@@ -42,6 +42,11 @@
   protected $logger;
 
   /**
+   * @var \Drupal\Core\Config\ImmutableConfig
+   */
+  protected $flood;
+
+  /**
    * Constructs a Drupal\rest\Plugin\ResourceBase object.
    *
    * @param array $configuration
@@ -55,10 +60,11 @@
    * @param \Psr\Log\LoggerInterface $logger
    *   A logger instance.
    */
-  public function __construct(array $configuration, $plugin_id, $plugin_definition, array $serializer_formats, LoggerInterface $logger) {
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, array $serializer_formats, LoggerInterface $logger, $flood) {
     parent::__construct($configuration, $plugin_id, $plugin_definition);
     $this->serializerFormats = $serializer_formats;
     $this->logger = $logger;
+    $this->flood = $flood;
   }
 
   /**
@@ -70,7 +76,9 @@ public static function create(ContainerInterface $container, array $configuratio
       $plugin_id,
       $plugin_definition,
       $container->getParameter('serializer.formats'),
-      $container->get('logger.factory')->get('rest')
+      $container->get('logger.factory')->get('rest'),
+      // FIX ME
+      \Drupal::flood()
     );
   }
 
@@ -210,4 +218,20 @@ protected function getBaseRoute($canonical_path, $method) {
     return $route;
   }
 
+  /**
+   * Checks for flooding.
+   *
+   * @param \Drupal\Core\Config\ImmutableConfig $config
+   * @param $name
+   * @return bool
+   */
+  protected function restFloodControl($config, $name) {
+    $limit = $config->get('user_limit');
+    $interval = $config->get('user_window');
+    if (!\Drupal::flood()->isAllowed($name, $limit, $interval)) {
+      return TRUE;
+    }
+    return FALSE;
+  }
+
 }
diff --git a/core/modules/rest/src/Plugin/rest/resource/UserLoginResource.php b/core/modules/rest/src/Plugin/rest/resource/UserLoginResource.php
new file mode 100644
index 0000000..cdad5ea
--- /dev/null
+++ b/core/modules/rest/src/Plugin/rest/resource/UserLoginResource.php
@@ -0,0 +1,101 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\rest\Plugin\rest\resource\UserLoginResource.
+ */
+
+namespace Drupal\rest\Plugin\rest\resource;
+
+use Drupal\rest\ResourceResponse;
+use Drupal\rest\Plugin\ResourceBase;
+use Drupal\user\Entity\User;
+
+/**
+ * Allows user logins by setting session cookies.
+ *
+ * @RestResource(
+ *   id = "user_login",
+ *   label = @Translation("User Login")
+ * )
+ */
+class UserLoginResource extends ResourceBase {
+
+  /**
+   * Responds to the user login POST requests and log in a user.
+   *
+   * @param string[] $operation
+   *   array(
+   *     'op' => 'login', 'logout'
+   *     'credentials' => array(
+   *       'name' => 'your-name',
+   *       'pass' => 'your-password',
+   *     ),
+   *   )
+   *
+   *   The operation and username + pass for the login op.
+   *
+   * @return \Drupal\rest\ResourceResponse
+   *   The HTTP response object.
+   */
+  public function post(array $operation = array()) {
+
+    switch ($operation['op']) {
+
+      case 'login':
+        if (!empty($operation['credentials'])) {
+          return $this->login($operation['credentials']);
+        }
+        return new ResourceResponse('credentials.', 400, array());
+
+      case 'logout':
+        return $this->logout();
+
+    }
+  }
+
+  /**
+   * User login.
+   *
+   * @param array $credentials
+   *   The username and pass for the user.
+   *
+   * @return \Drupal\rest\ResourceResponse
+   *   The HTTP response object
+   */
+  protected function login(array $credentials = array()) {
+    // Verify that the username is filled.
+    if (!array_key_exists('name', $credentials)) {
+      return new ResourceResponse('Missing credentials.name.', 400, array());
+    }
+    // Verify that the username is filled.
+    if (!array_key_exists('pass', $credentials)) {
+      return new ResourceResponse('Missing credentials.pass.', 400, array());
+    }
+
+    // Flood control.
+    if ($this->restFloodControl(\Drupal::config('user.flood'), 'rest.login_cookie')) {
+      return new ResourceResponse('Blocked.', 400, array());
+    }
+
+    // Log in the user.
+    if ($uid = \Drupal::service('user.auth')->authenticate($credentials['name'], $credentials['pass'])) {
+      $user = User::load($uid);
+      user_login_finalize($user);
+      return new ResourceResponse('You are logged in as ' . $credentials['name'], 200, array());
+    }
+    $this->flood->register('rest.login_cookie', \Drupal::config('user.flood')->get('user_window'));
+    return new ResourceResponse('Sorry, unrecognized username or password.', 400, array());
+  }
+
+  /**
+   * User Logout.
+   *
+   * @return ResourceResponse
+   */
+  protected function logout() {
+    user_logout();
+    return new ResourceResponse('Logged out!', 200, array());
+  }
+
+}
diff --git a/core/modules/rest/src/RequestHandler.php b/core/modules/rest/src/RequestHandler.php
index 2aa65ad..d7b3280 100644
--- a/core/modules/rest/src/RequestHandler.php
+++ b/core/modules/rest/src/RequestHandler.php
@@ -61,7 +61,13 @@ public function handle(RouteMatchInterface $route_match, Request $request) {
         $definition = $resource->getPluginDefinition();
         $class = $definition['serialization_class'];
         try {
-          $unserialized = $serializer->deserialize($received, $class, $format, array('request_method' => $method));
+          if ($class) {
+            $unserialized = $serializer->deserialize($received, $class, $format, array('request_method' => $method));
+          }
+          // Avoid denormalization because we need to instantiate a class.
+          else {
+            $unserialized = $serializer->decode($received, $format, array('request_method' => $method));
+          }
         }
         catch (UnexpectedValueException $e) {
           $error['error'] = $e->getMessage();
diff --git a/core/modules/rest/src/Tests/UserTest.php b/core/modules/rest/src/Tests/UserTest.php
new file mode 100644
index 0000000..b928677
--- /dev/null
+++ b/core/modules/rest/src/Tests/UserTest.php
@@ -0,0 +1,53 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\rest\test\AuthTest.
+ */
+
+namespace Drupal\rest\Tests;
+
+use Drupal\rest\Tests\RESTTestBase;
+
+/**
+ * Tests REST user login.
+ *
+ * @group rest
+ */
+class UserTest extends RESTTestBase {
+
+  /**
+   * Modules to install.
+   *
+   * @var array
+   */
+  public static $modules = array('basic_auth', 'hal', 'rest');
+
+  /**
+   * Tests login, status, logout.
+   */
+  public function testLogin() {
+    $this->enableService('user_login', 'POST');
+
+    $account = $this->drupalCreateUser();
+
+    $payload = array(
+      'op' => 'login',
+      'credentials' => array(
+        'name' => $account->getUsername(),
+        'pass' => $account->pass_raw,
+      ),
+    );
+
+    $this->httpRequest('user_login', 'POST', json_encode($payload), $this->defaultMimeType);
+    $this->assertResponse('200', 'Successfully logged into Drupal.');
+
+    $payload = array(
+      'op' => 'logout',
+    );
+
+    $this->httpRequest('user_login', 'POST', json_encode($payload), $this->defaultMimeType);
+    $this->assertResponse('200', 'Successfully logged out from Drupal.');
+
+  }
+}
