diff --git a/jsonapi.services.yml b/jsonapi.services.yml
index 2804940..126ffc1 100644
--- a/jsonapi.services.yml
+++ b/jsonapi.services.yml
@@ -51,6 +51,11 @@ services:
     arguments: ['@current_user']
     tags:
       - { name: normalizer, priority: 2 }
+  serializer.normalizer.entity_access_denied_exception.jsonapi:
+    class: Drupal\jsonapi\Normalizer\EntityAccessDeniedHttpExceptionNormalizer
+    arguments: ['@current_user']
+    tags:
+      - { name: normalizer, priority: 2 }
   serializer.encoder.jsonapi:
     class: Drupal\jsonapi\Encoder\JsonEncoder
     tags:
diff --git a/src/Controller/EntityResource.php b/src/Controller/EntityResource.php
index eab187e..c2a80ed 100644
--- a/src/Controller/EntityResource.php
+++ b/src/Controller/EntityResource.php
@@ -4,6 +4,7 @@ namespace Drupal\jsonapi\Controller;
 
 use Drupal\Component\Serialization\Json;
 use Drupal\Core\Access\AccessibleInterface;
+use Drupal\Core\Access\AccessResultReasonInterface;
 use Drupal\Core\Cache\CacheableMetadata;
 use Drupal\Core\Config\Entity\ConfigEntityInterface;
 use Drupal\Core\Entity\ContentEntityInterface;
@@ -15,6 +16,7 @@ use Drupal\Core\Entity\FieldableEntityInterface;
 use Drupal\Core\Field\EntityReferenceFieldItemListInterface;
 use Drupal\Core\Field\FieldTypePluginManagerInterface;
 use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
+use Drupal\jsonapi\Error\EntityAccessDeniedHttpException;
 use Drupal\jsonapi\Resource\EntityCollection;
 use Drupal\jsonapi\Resource\JsonApiDocumentTopLevel;
 use Drupal\jsonapi\ResourceType\ResourceType;
@@ -117,7 +119,15 @@ class EntityResource {
   public function getIndividual(EntityInterface $entity, Request $request, $response_code = 200) {
     $entity_access = $entity->access('view', NULL, TRUE);
     if (!$entity_access->isAllowed()) {
-      throw new SerializableHttpException(403, 'The current user is not allowed to GET the selected resource.');
+      $exception = new EntityAccessDeniedHttpException(403, 'The current user is not allowed to GET the selected resource.');
+      if ($entity_access instanceof AccessResultReasonInterface) {
+        $exception->addError($entity, '/data', $entity_access->getReason());
+      }
+      else {
+        $exception->addError($entity, '/data');
+      }
+
+      throw $exception;
     }
     $response = $this->buildWrappedResponse($entity, $response_code);
     return $response;
@@ -169,7 +179,15 @@ class EntityResource {
     $entity_access = $entity->access('create', NULL, TRUE);
 
     if (!$entity_access->isAllowed()) {
-      throw new SerializableHttpException(403, 'The current user is not allowed to POST the selected resource.');
+      $exception = new EntityAccessDeniedHttpException(403, 'The current user is not allowed to POST the selected resource.');
+      if ($entity_access instanceof AccessResultReasonInterface) {
+        $exception->addError($entity, '/data', $entity_access->getReason());
+      }
+      else {
+        $exception->addError($entity, '/data');
+      }
+
+      throw $exception;
     }
     $this->validate($entity);
     $entity->save();
@@ -192,7 +210,15 @@ class EntityResource {
   public function patchIndividual(EntityInterface $entity, EntityInterface $parsed_entity, Request $request) {
     $entity_access = $entity->access('update', NULL, TRUE);
     if (!$entity_access->isAllowed()) {
-      throw new SerializableHttpException(403, 'The current user is not allowed to PATCH the selected resource.');
+      $exception = new EntityAccessDeniedHttpException(403, 'The current user is not allowed to PATCH the selected resource.');
+      if ($entity_access instanceof AccessResultReasonInterface) {
+        $exception->addError($entity, '/data', $entity_access->getReason());
+      }
+      else {
+        $exception->addError($entity, '/data');
+      }
+
+      throw $exception;
     }
     $body = Json::decode($request->getContent());
     $data = $body['data'];
@@ -386,7 +412,16 @@ class EntityResource {
 
     $field_access = $field_list->access('edit', NULL, TRUE);
     if (!$field_access->isAllowed()) {
-      throw new SerializableHttpException(403, sprintf('The current user is not allowed to PATCH the selected field (%s).', $field_list->getName()));
+      $field_name = $field_list->getName();
+      $exception = new EntityAccessDeniedHttpException(403, sprintf('The current user is not allowed to PATCH the selected field (%s).', $field_name));
+      if ($field_access instanceof AccessResultReasonInterface) {
+        $exception->addError($entity, '/data/attributes/' . $field_name, $field_access->getReason());
+      }
+      else {
+        $exception->addError($entity, '/data/attributes/' . $field_name);
+      }
+
+      throw $exception;
     }
     // Time to save the relationship.
     foreach ($parsed_field_list as $field_item) {
@@ -501,7 +536,15 @@ class EntityResource {
     $field_name = $parsed_field_list->getName();
     $field_access = $parsed_field_list->access('edit', NULL, TRUE);
     if (!$field_access->isAllowed()) {
-      throw new SerializableHttpException(403, sprintf('The current user is not allowed to PATCH the selected field (%s).', $field_name));
+      $exception = new EntityAccessDeniedHttpException(403, sprintf('The current user is not allowed to PATCH the selected field (%s).', $field_name));
+      if ($field_access instanceof AccessResultReasonInterface) {
+        $exception->addError($entity, '/data/attributes/' . $field_name, $field_access->getReason());
+      }
+      else {
+        $exception->addError($entity, '/data/attributes/' . $field_name);
+      }
+
+      throw $exception;
     }
     /* @var \Drupal\Core\Field\EntityReferenceFieldItemListInterface $field_list */
     $field_list = $entity->{$related_field};
@@ -623,7 +666,14 @@ class EntityResource {
     /* @var \Drupal\Core\Field\EntityReferenceFieldItemListInterface $parsed_field_list */
     $entity_access = $entity->access('update', NULL, TRUE);
     if (!$entity_access->isAllowed()) {
-      throw new SerializableHttpException(403, 'The current user is not allowed to update the selected resource.');
+      $exception = new EntityAccessDeniedHttpException(403, 'The current user is not allowed to update the selected resource.');
+      if ($entity_access instanceof AccessResultReasonInterface) {
+        $exception->addError($entity, $related_field, $entity_access->getReason());
+      }
+      else {
+        $exception->addError($entity, $related_field);
+      }
+      throw $exception;
     }
     if (!($field_list = $entity->get($related_field)) || !$this->isRelationshipField($field_list)) {
       throw new SerializableHttpException(404, sprintf('The relationship %s is not present in this resource.', $related_field));
@@ -652,7 +702,15 @@ class EntityResource {
       if ($destination_field_list->getValue() != $origin_field_list->getValue()) {
         $field_access = $destination_field_list->access('edit', NULL, TRUE);
         if (!$field_access->isAllowed()) {
-          throw new SerializableHttpException(403, sprintf('The current user is not allowed to PATCH the selected field (%s).', $destination_field_list->getName()));
+          $exception = new EntityAccessDeniedHttpException(403, sprintf('The current user is not allowed to PATCH the selected field (%s).', $destination_field_list->getName()));
+          if ($field_access instanceof AccessResultReasonInterface) {
+            $exception->addError($destination, '/data/attributes/' . $field_name, $field_access->getReason());
+          }
+          else {
+            $exception->addError($destination, '/data/attributes/' . $field_name);
+          }
+
+          throw $exception;
         }
         $destination->{$field_name} = $origin->get($field_name);
       }
diff --git a/src/Error/EntityAccessDeniedHttpException.php b/src/Error/EntityAccessDeniedHttpException.php
new file mode 100644
index 0000000..1816cc3
--- /dev/null
+++ b/src/Error/EntityAccessDeniedHttpException.php
@@ -0,0 +1,63 @@
+<?php
+
+namespace Drupal\jsonapi\Error;
+
+use Drupal\Core\Entity\EntityInterface;
+
+class EntityAccessDeniedHttpException extends SerializableHttpException {
+
+  /**
+   * The entities, which the current user doesn't have access to.
+   *
+   * @var \Drupal\Core\Entity\EntityInterface[]
+   */
+  protected $entities = [];
+
+  /**
+   * @var string[]
+   */
+  protected $pointers;
+
+  /**
+   * @var string[]
+   */
+  protected $reasons;
+
+  /**
+   * UnprocessableHttpEntityException constructor.
+   *
+   * @param \Exception|null $previous
+   * @param array $headers
+   * @param int $code
+   */
+  public function __construct(\Exception $previous = NULL, array $headers = array(), $code = 0) {
+    parent::__construct(403, 'The current user is not allowed to GET the selected resource.', $previous, $headers, $code);
+  }
+
+  /**
+   * The entity.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity.
+   *
+   * @return $this
+   */
+  public function addError(EntityInterface $entity, $pointer, $reason = NULL) {
+    $this->entities[] = $entity;
+    $this->pointers[] = $pointer;
+    $this->reasons[] = $reason;
+
+    return $this;
+  }
+
+  public function getErrors() {
+    return array_map(function ($index) {
+      return [
+        $this->entities[$index],
+        $this->pointers[$index],
+        $this->reasons[$index],
+      ];
+    }, array_keys($this->entities));
+  }
+
+}
diff --git a/src/Normalizer/EntityAccessDeniedHttpExceptionNormalizer.php b/src/Normalizer/EntityAccessDeniedHttpExceptionNormalizer.php
new file mode 100644
index 0000000..e04967a
--- /dev/null
+++ b/src/Normalizer/EntityAccessDeniedHttpExceptionNormalizer.php
@@ -0,0 +1,47 @@
+<?php
+
+namespace Drupal\jsonapi\Normalizer;
+
+use Drupal\Core\Session\AccountProxyInterface;
+use Drupal\jsonapi\Error\EntityAccessDeniedHttpException;
+use Drupal\jsonapi\Error\UnprocessableHttpEntityException;
+use Symfony\Component\HttpKernel\Exception\HttpException;
+
+/**
+ * Normalizes an EntityAccessDeniedException object for JSON output which
+ * complies with the JSON API specification. A source pointer is added to help
+ * client applications report to know which entity was access denied.
+ *
+ * @see http://jsonapi.org/format/#error-objects
+ */
+class EntityAccessDeniedHttpExceptionNormalizer extends HttpExceptionNormalizer {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function buildErrorObjects(HttpException $exception) {
+    /** @var $exception \Drupal\jsonapi\Error\EntityAccessDeniedHttpException */
+    $errors = parent::buildErrorObjects($exception);
+    $error = $errors[0];
+    unset($error['links']);
+
+    $errors = [];
+
+    foreach ($exception->getErrors() as list($entity, $field_name, $reason)) {
+      /** @var \Drupal\Core\Entity\EntityInterface $entity */
+      $error['id'] = $entity->uuid();
+
+      // @todo Figure out how to support relationships.
+      $error['source']['pointer'] = $field_name ? '/data/relationships/' . $field_name : '/data';
+
+      if ($reason) {
+        $error['detail']['message'] = $reason;
+      }
+
+      $errors[] = $error;
+    }
+
+    return $errors;
+  }
+
+}
diff --git a/tests/src/Functional/JsonApiFunctionalTest.php b/tests/src/Functional/JsonApiFunctionalTest.php
index 87fdadb..0deb97c 100644
--- a/tests/src/Functional/JsonApiFunctionalTest.php
+++ b/tests/src/Functional/JsonApiFunctionalTest.php
@@ -482,6 +482,8 @@ class JsonApiFunctionalTest extends BrowserTestBase {
     $created_response = Json::decode($response->getBody()->__toString());
     $this->assertEquals(403, $response->getStatusCode());
     $this->assertNotEmpty($created_response['errors']);
+    $this->assertEmpty($created_response['errors'][0]['id']);
+    $this->assertEquals(403, $created_response['errors'][0]['status']);
     $this->assertEquals('Forbidden', $created_response['errors'][0]['title']);
     // 3. Missing Content-Type error.
     $response = $this->request('POST', $collection_url, [
@@ -564,6 +566,10 @@ class JsonApiFunctionalTest extends BrowserTestBase {
     $updated_response = Json::decode($response->getBody()->__toString());
     $this->assertEquals(403, $response->getStatusCode());
     $this->assertEquals('The current user is not allowed to PATCH the selected field (status).', $updated_response['errors'][0]['detail']);
+    $this->assertEquals($uuid, $created_response['errors'][0]['id']);
+    $this->assertEquals(['pointer' => '/data'], $created_response['errors'][0]['source']);
+    $this->assertEquals(403, $created_response['errors'][0]['status']);
+
     $node = \Drupal::entityManager()->loadEntityByUuid('node', $uuid);
     $this->assertEquals(1, $node->get('status')->value, 'Node status was not changed.');
     // 9. Successful POST to related endpoint.
