Use case:

I have two roles: "Teacher" and "Student". Each Teacher has been assigned a set of Students.

This relationship is tracked by a custom entity: "Students by teacher" which has two fields:

  1. Teacher (single value) - a teacher.
  2. Student (unlimited values) - the set of Students supervised by this teacher.

There is also a custom node content type called "Assignment". Upon completion of an assignment, a student will save it in the Drupal database as a published node.

The Teachers have the permission "View published content". This means that with my current setup, all Teachers can view all published assignments, whether the author is a student they supervise or not.

What I want is this: If the assignment is authored by a Student they supervise, they shall see it. If it is not, they get a 403 ("Access denied") response.

I've been looking for a Drupal extension to solve this, and the best one I've found is Flexi Access. That extension has not been upgraded to Drupal 9, so I cannot use it.

I've been thinking about solving this by means of some hook that is ran when a user tries to view a node. The logic inside the hook shall be this:

  1. Check if the author of the node is supervised by the person trying to view the node.

  2. If "Yes", show the node. If "No", show "Access denied".

However, I've searched the API, and have so far not been able to find a hook (or some other means) that let me do this.

Somewhere at the back of my brain, I have a notion that Drupal 9 provides some other mechanism than hooks for implementing access control.

Question: How do I provide a 403 response when a user tries to view a node and some specific criteria is not satisfied?

1 Answer 1


Found out just after posting this question.

One can use hook_ENTITY_TYPE_access() like this:

use Drupal\Core\Access\AccessResult;
use Drupal\Core\Session\AccountInterface;
use Drupal\node\NodeInterface;

function mymodule_node_access(NodeInterface $node, $op, AccountInterface $account) {
  if ('view' == $op && CONTITION NOT SATISFIED) {
    return AccessResult::forbidden();
  return AccessResult::neutral();

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.