I would like to give access some private pdf files to only logged in users.

I have this in my htaccess:

RewriteCond %{REQUEST_FILENAME} ^.*(pdf)$
RewriteCond %{HTTP_COOKIE} !^.*wordpress_logged_in.*$ [NC]
RewriteRule . - [R=403,L]

But I want to restrict access only documents .pdf with name starts with "private_".

Example: private_document1.pdf and private_document2.pdf only have to be accessible by logged in users.

Please, any ideas?

  • 1
    there is no point to check if a cookie exist if you do not validate it. This do not give you the protection you think it gives. Apr 5, 2016 at 18:37

1 Answer 1


Your approach does not provide security. I could hand-craft a cookie named "wordpress_logged_in" (containing any arbitrary value) and have access to your PDF files.

You may want to rethink your solution to put a PHP script in between the files and the users.


  1. User Clicks download button
  2. PHP Script handles fetching document
  3. If authenticated user, PHP script sends through PDF file.
  4. If not authenticated, send error message.

Take a look at this answer for more detail on implementation: https://stackoverflow.com/questions/10834196/secure-files-for-download

If this is an approach you would like to explore, I will update my answer with how to connect this approach to WordPress.

Edit: I'm going to provide a "hacky" solution for proof-of-concept. In practice, I would likely implement the approach using WP AJAX actions.


 * Assume WordPress lives in /var/www/mysite/
 * This script's path is /var/www/mysite/downloader.php
 * To download a file, link the user to:
 *   <a href="/downloader.php">Download file</a>
 * You can mask this downloader using htaccess rewrites

// Load wordpress

if (!is_user_logged_in()) die('no access');

// specify a file path
$file = '/path/to/file/outside/www/secret.pdf';

// or load the file from some other location (e.g. WP Media)

header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=' . basename($file));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . filesize($file));

// Don't use closing PHP brackets.
  • Thanks for your answer. You're right. I would like to explore your solution. I'd appreciate, If you could update your answer with how to connect this approach to WordPress. Apr 5, 2016 at 23:21
  • I made a quick update using the "dirty" solution.. i.e. using an external script. If you want a more elegant solution, use AJAX Apr 7, 2016 at 16:17

Your Answer

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

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