diff --git a/core/modules/jsonld/lib/Drupal/jsonld/JsonldEntityWrapper.php b/core/modules/jsonld/lib/Drupal/jsonld/JsonldEntityWrapper.php
index a2e49e3..f96f114 100644
--- a/core/modules/jsonld/lib/Drupal/jsonld/JsonldEntityWrapper.php
+++ b/core/modules/jsonld/lib/Drupal/jsonld/JsonldEntityWrapper.php
@@ -111,6 +111,7 @@ public function getTypeUri() {
   public function getProperties() {
     // Properties to skip.
     $skip = array('id');
+    $properties = array();
 
     // Create language map property structure.
     foreach ($this->entity->getTranslationLanguages() as $langcode => $language) {
diff --git a/core/modules/rest/lib/Drupal/rest/Plugin/rest/resource/EntityResource.php b/core/modules/rest/lib/Drupal/rest/Plugin/rest/resource/EntityResource.php
index 47d1b0b..77bcc00 100644
--- a/core/modules/rest/lib/Drupal/rest/Plugin/rest/resource/EntityResource.php
+++ b/core/modules/rest/lib/Drupal/rest/Plugin/rest/resource/EntityResource.php
@@ -13,6 +13,7 @@
 use Drupal\Core\Entity\EntityStorageException;
 use Drupal\rest\Plugin\ResourceBase;
 use Drupal\rest\ResourceResponse;
+use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
 use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
 use Symfony\Component\HttpKernel\Exception\HttpException;
 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
@@ -44,6 +45,14 @@ public function get($id) {
     $definition = $this->getDefinition();
     $entity = entity_load($definition['entity_type'], $id);
     if ($entity) {
+      if (!$entity->access('view')) {
+        throw new AccessDeniedHttpException();
+      }
+      foreach ($entity as $field_name => $field) {
+        if (!$field->access('view')) {
+          unset($entity->{$field_name});
+        }
+      }
       return new ResourceResponse($entity);
     }
     throw new NotFoundHttpException(t('Entity with ID @id not found', array('@id' => $id)));
@@ -63,6 +72,9 @@ public function get($id) {
    * @throws \Symfony\Component\HttpKernel\Exception\HttpException
    */
   public function post($id, EntityInterface $entity) {
+    if (!$entity->access('create')) {
+      throw new AccessDeniedHttpException();
+    }
     $definition = $this->getDefinition();
     // Verify that the deserialized entity is of the type that we expect to
     // prevent security issues.
@@ -74,6 +86,11 @@ public function post($id, EntityInterface $entity) {
     if (!$entity->isNew()) {
       throw new BadRequestHttpException(t('Only new entities can be created'));
     }
+    foreach ($entity as $field_name => $field) {
+      if (!$field->access('create')) {
+        throw new AccessDeniedHttpException(t('Access denied on creating field @field.', array('@field' => $field_name)));
+      }
+    }
     try {
       $entity->save();
       watchdog('rest', 'Created entity %type with ID %id.', array('%type' => $entity->entityType(), '%id' => $entity->id()));
@@ -114,10 +131,27 @@ public function patch($id, EntityInterface $entity) {
     if ($original_entity == FALSE) {
       throw new NotFoundHttpException();
     }
+    if (!$original_entity->access('update')) {
+      throw new AccessDeniedHttpException();
+    }
+    $info = $original_entity->entityInfo();
+    // Make sure that the entity ID is the one provided in the URL.
+    $entity->{$info['entity_keys']['id']} = $id;
+
     // Overwrite the received properties.
-    foreach ($entity->getProperties() as $name => $property) {
-      if (isset($entity->{$name})) {
-        $original_entity->{$name} = $property;
+    foreach ($entity as $field_name => $field) {
+      if (isset($entity->{$field_name})) {
+        if (empty($entity->{$field_name})) {
+          if (!$original_entity->{$field_name}->access('delete')) {
+            throw new AccessDeniedHttpException(t('Access denied on deleting field @field.', array('@field' => $field_name)));
+          }
+        }
+        else {
+          if (!$original_entity->{$field_name}->access('update')) {
+            throw new AccessDeniedHttpException(t('Access denied on updating field @field.', array('@field' => $field_name)));
+          }
+        }
+        $original_entity->{$field_name} = $field;
       }
     }
     try {
@@ -147,6 +181,9 @@ public function delete($id) {
     $definition = $this->getDefinition();
     $entity = entity_load($definition['entity_type'], $id);
     if ($entity) {
+      if (!$entity->access('delete')) {
+        throw new AccessDeniedHttpException();
+      }
       try {
         $entity->delete();
         watchdog('rest', 'Deleted entity %type with ID %id.', array('%type' => $entity->entityType(), '%id' => $entity->id()));
@@ -160,18 +197,4 @@ public function delete($id) {
     }
     throw new NotFoundHttpException(t('Entity with ID @id not found', array('@id' => $id)));
   }
-
-  /**
-   * Overrides ResourceBase::permissions().
-   */
-  public function permissions() {
-    $permissions = parent::permissions();
-    // Mark all items as administrative permissions for now.
-    // @todo Remove this restriction once proper entity access control is
-    // implemented. See http://drupal.org/node/1866908
-    foreach ($permissions as $name => $permission) {
-      $permissions[$name]['restrict access'] = TRUE;
-    }
-    return $permissions;
-  }
 }
diff --git a/core/modules/rest/lib/Drupal/rest/Tests/CreateTest.php b/core/modules/rest/lib/Drupal/rest/Tests/CreateTest.php
index d6973e5..32784a8 100644
--- a/core/modules/rest/lib/Drupal/rest/Tests/CreateTest.php
+++ b/core/modules/rest/lib/Drupal/rest/Tests/CreateTest.php
@@ -41,7 +41,9 @@ public function testCreate() {
     $this->enableService('entity:' . $entity_type, 'POST');
     // Create a user account that has the required permissions to create
     // resources via the REST API.
-    $account = $this->drupalCreateUser(array('restful post entity:' . $entity_type));
+    $permissions = $this->entityPermissions($entity_type, 'create');
+    $permissions[] = 'restful post entity:' . $entity_type;
+    $account = $this->drupalCreateUser($permissions);
     $this->drupalLogin($account);
 
     $entity_values = $this->entityValues($entity_type);
@@ -70,6 +72,18 @@ public function testCreate() {
 
     $loaded_entity->delete();
 
+    // Try to create an entity with an access protected field.
+    // @see entity_test_entity_field_access()
+    $entity->field_test_text->value = 'no access value';
+    $serialized = $serializer->serialize($entity, 'drupal_jsonld');
+    $this->httpRequest('entity/' . $entity_type, 'POST', $serialized, 'application/vnd.drupal.ld+json');
+    $this->assertResponse(403);
+    $this->assertFalse(entity_load_multiple($entity_type, NULL, TRUE), 'No entity has been created in the database.');
+
+    // Restore the valid test value.
+    $entity->field_test_text->value = $entity_values['field_test_text'][0]['value'];
+    $serialized = $serializer->serialize($entity, 'drupal_jsonld');
+
     // Try to send invalid data that cannot be correctly deserialized.
     $this->httpRequest('entity/' . $entity_type, 'POST', 'kaboom!', 'application/vnd.drupal.ld+json');
     $this->assertResponse(400);
diff --git a/core/modules/rest/lib/Drupal/rest/Tests/DeleteTest.php b/core/modules/rest/lib/Drupal/rest/Tests/DeleteTest.php
index 2bed8ba..7f72ee7 100644
--- a/core/modules/rest/lib/Drupal/rest/Tests/DeleteTest.php
+++ b/core/modules/rest/lib/Drupal/rest/Tests/DeleteTest.php
@@ -34,12 +34,16 @@ public static function getInfo() {
    */
   public function testDelete() {
     // Define the entity types we want to test.
-    $entity_types = array('entity_test', 'node', 'user');
+    // @todo expand this test to at least nodes and users once their access
+    // controllers are implemented.
+    $entity_types = array('entity_test');
     foreach ($entity_types as $entity_type) {
       $this->enableService('entity:' . $entity_type, 'DELETE');
       // Create a user account that has the required permissions to delete
       // resources via the REST API.
-      $account = $this->drupalCreateUser(array('restful delete entity:' . $entity_type));
+      $permissions = $this->entityPermissions($entity_type, 'delete');
+      $permissions[] = 'restful delete entity:' . $entity_type;
+      $account = $this->drupalCreateUser($permissions);
       $this->drupalLogin($account);
 
       // Create an entity programmatically.
diff --git a/core/modules/rest/lib/Drupal/rest/Tests/RESTTestBase.php b/core/modules/rest/lib/Drupal/rest/Tests/RESTTestBase.php
index 6cbfbd8..cd9bc22 100644
--- a/core/modules/rest/lib/Drupal/rest/Tests/RESTTestBase.php
+++ b/core/modules/rest/lib/Drupal/rest/Tests/RESTTestBase.php
@@ -218,4 +218,29 @@ protected function drupalLogin($user) {
     }
     parent::drupalLogin($user);
   }
+
+  /**
+   * Provides the necessary user permissions for entity operations.
+   *
+   * @param string $entity_type
+   *   The entity type.
+   * @param type $operation
+   *   The operation, one of 'view', 'create', 'update' or 'delete'.
+   *
+   * @return array
+   *   The set of user permission strings.
+   */
+  protected function entityPermissions($entity_type, $operation) {
+    switch ($entity_type) {
+      case 'entity_test':
+        switch ($operation) {
+          case 'view':
+            return array('view test entity');
+          case 'create':
+          case 'update':
+          case 'delete':
+            return array('administer entity_test content');
+        }
+    }
+  }
 }
diff --git a/core/modules/rest/lib/Drupal/rest/Tests/ReadTest.php b/core/modules/rest/lib/Drupal/rest/Tests/ReadTest.php
index e157a2d..f3ccca7 100644
--- a/core/modules/rest/lib/Drupal/rest/Tests/ReadTest.php
+++ b/core/modules/rest/lib/Drupal/rest/Tests/ReadTest.php
@@ -39,9 +39,11 @@ public function testRead() {
     $entity_types = array('entity_test');
     foreach ($entity_types as $entity_type) {
       $this->enableService('entity:' . $entity_type, 'GET');
-      // Create a user account that has the required permissions to delete
+      // Create a user account that has the required permissions to read
       // resources via the REST API.
-      $account = $this->drupalCreateUser(array('restful get entity:' . $entity_type));
+      $permissions = $this->entityPermissions($entity_type, 'view');
+      $permissions[] = 'restful get entity:' . $entity_type;
+      $account = $this->drupalCreateUser($permissions);
       $this->drupalLogin($account);
 
       // Create an entity programmatically.
@@ -66,6 +68,17 @@ public function testRead() {
       $decoded = drupal_json_decode($response);
       $this->assertEqual($decoded['error'], 'Entity with ID 9999 not found', 'Response message is correct.');
 
+      // Make sure that field level access works and that the according field is
+      // not available in the response.
+      // @see entity_test_entity_field_access()
+      $entity->field_test_text->value = 'no access value';
+      $entity->save();
+      $response = $this->httpRequest('entity/' . $entity_type . '/' . $entity->id(), 'GET', NULL, 'application/vnd.drupal.ld+json');
+      $this->assertResponse(200);
+      $this->assertHeader('content-type', 'application/vnd.drupal.ld+json');
+      $data = drupal_json_decode($response);
+      $this->assertFalse(isset($data['field_test_text']), 'Field access protexted field is not visible in the response.');
+
       // Try to read an entity without proper permissions.
       $this->drupalLogout();
       $response = $this->httpRequest('entity/' . $entity_type . '/' . $entity->id(), 'GET', NULL, 'application/vnd.drupal.ld+json');
diff --git a/core/modules/rest/lib/Drupal/rest/Tests/UpdateTest.php b/core/modules/rest/lib/Drupal/rest/Tests/UpdateTest.php
index 31c6461..44ea063 100644
--- a/core/modules/rest/lib/Drupal/rest/Tests/UpdateTest.php
+++ b/core/modules/rest/lib/Drupal/rest/Tests/UpdateTest.php
@@ -41,7 +41,9 @@ public function testPatchUpdate() {
     $this->enableService('entity:' . $entity_type, 'PATCH');
     // Create a user account that has the required permissions to create
     // resources via the REST API.
-    $account = $this->drupalCreateUser(array('restful patch entity:' . $entity_type));
+    $permissions = $this->entityPermissions($entity_type, 'update');
+    $permissions[] = 'restful patch entity:' . $entity_type;
+    $account = $this->drupalCreateUser($permissions);
     $this->drupalLogin($account);
 
     // Create an entity and save it to the database.
@@ -76,6 +78,32 @@ public function testPatchUpdate() {
     $entity = entity_load($entity_type, $entity->id(), TRUE);
     $this->assertNull($entity->field_test_text->value, 'Test field has been cleared.');
 
+    // Enable access protection for the text field.
+    // @see entity_test_entity_field_access()
+    $entity->field_test_text->value = 'no access value';
+    $entity->save();
+
+    // Try to empty a field that is access protected.
+    $this->httpRequest('entity/' . $entity_type . '/' . $entity->id(), 'PATCH', $serialized, 'application/vnd.drupal.ld+json');
+    $this->assertResponse(403);
+
+    // Re-load the entity from the database.
+    $entity = entity_load($entity_type, $entity->id(), TRUE);
+    $this->assertEqual($entity->field_test_text->value, 'no access value', 'Text field was not updated.');
+
+    // Try to update an access protected field.
+    $serialized = $serializer->serialize($patch_entity, 'drupal_jsonld');
+    $this->httpRequest('entity/' . $entity_type . '/' . $entity->id(), 'PATCH', $serialized, 'application/vnd.drupal.ld+json');
+    $this->assertResponse(403);
+
+    // Re-load the entity from the database.
+    $entity = entity_load($entity_type, $entity->id(), TRUE);
+    $this->assertEqual($entity->field_test_text->value, 'no access value', 'Text field was not updated.');
+
+    // Restore the valid test value.
+    $entity->field_test_text->value = $this->randomString();
+    $entity->save();
+
     // Try to update a non-existing entity with ID 9999.
     $this->httpRequest('entity/' . $entity_type . '/9999', 'PATCH', $serialized, 'application/vnd.drupal.ld+json');
     $this->assertResponse(404);
diff --git a/core/modules/system/tests/modules/entity_test/entity_test.module b/core/modules/system/tests/modules/entity_test/entity_test.module
index 9720399..80f1b39 100644
--- a/core/modules/system/tests/modules/entity_test/entity_test.module
+++ b/core/modules/system/tests/modules/entity_test/entity_test.module
@@ -289,8 +289,13 @@ function entity_test_entity_view_mode_info() {
  * @see \Drupal\system\Tests\Entity\FieldAccessTest::testFieldAccess()
  */
 function entity_test_entity_field_access($operation, $field, $account) {
-  if ($field->getName() == 'field_test_text' && $field->value == 'no access value') {
-    return FALSE;
+  if ($field->getName() == 'field_test_text') {
+    if ($field->value == 'no access value') {
+      return FALSE;
+    }
+    elseif ($operation == 'delete' && $field->value == 'no delete access value') {
+      return FALSE;
+    }
   }
 }
 
