diff --git a/core/modules/jsonapi/src/JsonApiResource/ResourceObject.php b/core/modules/jsonapi/src/JsonApiResource/ResourceObject.php
index 973bde3..5ab0a21 100644
--- a/core/modules/jsonapi/src/JsonApiResource/ResourceObject.php
+++ b/core/modules/jsonapi/src/JsonApiResource/ResourceObject.php
@@ -35,6 +35,13 @@ class ResourceObject implements CacheableDependencyInterface, ResourceIdentifier
   use CacheableDependencyTrait;
   use ResourceIdentifierTrait;
 
+  /**
+   * The module handler.
+   *
+   * @var \Drupal\Core\Extension\ModuleHandlerInterface
+   */
+  protected static $moduleHandler;
+
   /**
    * The resource object's version identifier.
    *
@@ -198,6 +205,18 @@ class ResourceObject implements CacheableDependencyInterface, ResourceIdentifier
     throw new \LogicException('A Url does not exist for this resource object because its resource type is not locatable.');
   }
 
+  /**
+   * Get the module handler.
+   *
+   * @return \Drupal\Core\Extension\ModuleHandlerInterface
+   */
+  protected static function getModuleHandler() {
+    if (!static::$moduleHandler) {
+      static::$moduleHandler = \Drupal::moduleHandler();
+    }
+    return static::$moduleHandler;
+  }
+
   /**
    * Extracts the entity's fields.
    *
@@ -259,6 +278,16 @@ class ResourceObject implements CacheableDependencyInterface, ResourceIdentifier
         $links = $links->withLink('self', new Link(new CacheableMetadata(), $self_url, 'self'));
       }
     }
+
+    // Invoke hook_jsonapi_resource_entity_links_alter() and
+    // hook_jsonapi_resource_entity_ENTITY_TYPE_links_alter()
+    // for each module.
+    $context = ['resource_type' => $resource_type, 'entity' => $entity];
+    static::getModuleHandler()->alter([
+      'jsonapi_resource_entity_links',
+      'jsonapi_resource_entity_' . $entity->getEntityTypeId() . '_links',
+    ], $links, $context);
+
     return $links;
   }
 
