In the site I am developing, the private files directory is outside the document root.
I have a content type (Chapter) with a file field that stores its files in the private files directory. When a Chapter node is published, its file is accessible to users, but when the node is unpublished, its file is not accessible to users. They get an access denied page.

How can I control the access to the attached file and allow users to access the attached file when the node is unpublished, in a custom module?

2 Answers 2


With Drupal, the access to private files is determined by access to the entity to which they are attached. I would create a new media entity type, setting the file storage to be private. Then you can set up custom access rules for the entity type, using standard Drupal methodology. Users with access to that entity will be allowed to access the private file, and users without access to that entity will be denied access to the file. Then you can attach the media item to whichever node or other entity you need.

  • Thanks for this suggestion @Jaypan. Each chapter node has a public checkbox that controls whether the pdf for it can be accessed by other than admin users. In addition, the book node that is parent to the chapter node has a public checkbox that overrides the public checkbox for its chapters. So I need to check both of those field values to determine whether the pdf for a chapter should be publicly viewable. Will your suggested approach allow for that? Commented Feb 13, 2022 at 4:13
  • Well, I explained how you manage permissions for private files. So if you configure your permissions on the Media type to follow your descriptions, then yes, my approach will allow for that. As to how you will actually set up those permissions on the media type, that's really a different topic, so you should open a new question if you want more information on that. Drupal Answers is a 1 question - 1 answer format site.
    – Jaypan
    Commented Feb 13, 2022 at 17:40
  • Thanks @Jaypan. I have limited experience with many areas of Drupal development, including this area. I'll give it a try and be back. Commented Feb 14, 2022 at 20:23
  • it seems that it does not work as it should be
    – Matoeil
    Commented Jan 16, 2023 at 16:06
  • drupal.org/project/drupal/issues/2904842
    – Matoeil
    Commented Jan 16, 2023 at 16:23

The expected normal behaviour described above does not seem to work. i Have had to :

use Drupal\Core\Access\AccessResult;
use Drupal\Core\Session\AccountInterface;
use Drupal\node\NodeInterface;
use Drupal\user\Entity\User;
use Drupal\media\MediaInterface;

function my_module_media_access(MediaInterface $media, $op, AccountInterface $account) {

  if ($op !== 'view') {
    return AccessResult::neutral();

  $user = User::load($account->id());
  if ($media->bundle() === 'media_private') {
    $acces = AccessResult::forbidden();
    if ($user->hasRole('private access people') || $user->hasRole('administrator')) {
      $acces = AccessResult::neutral();
    return $acces;
  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.