diff --git a/core/modules/rest/src/Plugin/ResourceBase.php b/core/modules/rest/src/Plugin/ResourceBase.php
index d0d22a3..0babfb7 100644
--- a/core/modules/rest/src/Plugin/ResourceBase.php
+++ b/core/modules/rest/src/Plugin/ResourceBase.php
@@ -216,4 +216,18 @@ protected function getBaseRoute($canonical_path, $method) {
     return $route;
   }
 
+  /**
+   * Throws an exception if the current user triggers flood control.
+   *
+   * @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
+   */
+  protected function restFloodControl($config, $event) {
+    $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..966897e
--- /dev/null
+++ b/core/modules/rest/src/Plugin/rest/resource/UserLoginResource.php
@@ -0,0 +1,93 @@
+<?php
+
+/**
+ * @file
+ * Definition of 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;
+
+/**
+ * Represents user login as resource.
+ *
+ * @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 array $operation
+   *   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('Missing name and pass.', 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 username.', 400, array());
+    }
+    // Verify that the username is filled.
+    if (!array_key_exists('pass', $credentials)) {
+      return new ResourceResponse('Missing 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());
+    }
+    \Drupal::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());
+  }
+
+}
\ No newline at end of file
diff --git a/core/modules/rest/src/RequestHandler.php b/core/modules/rest/src/RequestHandler.php
index 0ddfdd7..0cb2ef9 100644
--- a/core/modules/rest/src/RequestHandler.php
+++ b/core/modules/rest/src/RequestHandler.php
@@ -63,7 +63,13 @@ public function handle(RouteMatchInterface $route_match, Request $request, Route
         $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();
