title: Drupal - Install module - Access denied in administrator
body: <p><strong>Context</strong> : I'm working on a Drupal 8 project and want to add new modules.</p>
  
  <p><strong>Problem</strong>: when I try to install new module through the web interface (logged as admin user), I get the error message: </p>
  
  <blockquote>
    <p>Access denied, You are not authorized to access this page.</p>
  </blockquote>
  
  <p>The problem I have is exactly the same as this <a href="https://www.drupal.org/project/drupal/issues/2764541#comment-13517707" rel="nofollow noreferrer">problem</a>. However, there are no clear solutions. I tried to play with <code>allow_authorize_operations</code> parameters in <code>setting.php</code> file, <code>.htaccess</code> file and files permissions without success.</p>
  
  <p>After reading this similar <a href="https://www.drupal.org/forum/support/post-installation/2011-04-03/access-denied-when-trying-to-change-theme" rel="nofollow noreferrer">issue</a>, I suspect the problem is about the <code>.htaccess</code> or the <code>site.conf</code> file. I'm not confortable with these 2 files and suspect I'm missing something: </p>
  
  <hr>
  
  <p>Edit: I founded this interesting <a href="https://www.drupal.org/node/2612160" rel="nofollow noreferrer">discussion</a>. They highlight in comment <a href="https://www.drupal.org/project/drupal/issues/2612160#comment-11869254" rel="nofollow noreferrer">#35</a> also a similar issue. The problems might come from the fact that the <code>index.php</code> belongs to the <code>web</code> folder. To clean the URL, I apply the following in root directory:</p>
  
  <p><code>.htaccess</code></p>
  
  <pre><code>RewriteEngine on
  RewriteRule (.*) web/$1 [L]
  </code></pre>
  
  <p><strong>All files</strong>:
  <code>web/.htaccess</code></p>
  
  <pre><code>#
  # Apache/PHP/Drupal settings:
  #
  
  # Protect files and directories from prying eyes.
  &lt;FilesMatch "\.(engine|inc|install|make|module|profile|po|sh|.*sql|theme|twig|tpl(\.php)?|xtmpl|yml)(~|\.sw[op]|\.bak|\.orig|\.save)?$|^(\.(?!well-known).*|Entries.*|Repository|Root|Tag|Template|composer\.(json|lock)|web\.config)$|^#.*#$|\.php(~|\.sw[op]|\.bak|\.orig|\.save)$"&gt;
    &lt;IfModule mod_authz_core.c&gt;
      Require all denied
    &lt;/IfModule&gt;
    &lt;IfModule !mod_authz_core.c&gt;
      Order allow,deny
    &lt;/IfModule&gt;
  &lt;/FilesMatch&gt;
  
  # Don't show directory listings for URLs which map to a directory.
  Options -Indexes
  
  # Set the default handler.
  DirectoryIndex index.php index.html index.htm
  
  # Add correct encoding for SVGZ.
  AddType image/svg+xml svg svgz
  AddEncoding gzip svgz
  
  # Most of the following PHP settings cannot be changed at runtime. See
  # sites/default/default.settings.php and
  # Drupal\Core\DrupalKernel::bootEnvironment() for settings that can be
  # changed at runtime.
  
  # PHP 5, Apache 1 and 2.
  &lt;IfModule mod_php5.c&gt;
    php_value assert.active                   0
    php_flag session.auto_start               off
    php_value mbstring.http_input             pass
    php_value mbstring.http_output            pass
    php_flag mbstring.encoding_translation    off
    # PHP 5.6 has deprecated $HTTP_RAW_POST_DATA and produces warnings if this is
    # not set.
    php_value always_populate_raw_post_data   -1
  &lt;/IfModule&gt;
  
  # Requires mod_expires to be enabled.
  &lt;IfModule mod_expires.c&gt;
    # Enable expirations.
    ExpiresActive On
  
    # Cache all files for 2 weeks after access (A).
    ExpiresDefault A1209600
  
    &lt;FilesMatch \.php$&gt;
      # Do not allow PHP scripts to be cached unless they explicitly send cache
      # headers themselves. Otherwise all scripts would have to overwrite the
      # headers set by mod_expires if they want another caching behavior. This may
      # fail if an error occurs early in the bootstrap process, and it may cause
      # problems if a non-Drupal PHP file is installed in a subdirectory.
      ExpiresActive Off
    &lt;/FilesMatch&gt;
  &lt;/IfModule&gt;
  
  # Set a fallback resource if mod_rewrite is not enabled. This allows Drupal to
  # work without clean URLs. This requires Apache version &gt;= 2.2.16. If Drupal is
  # not accessed by the top level URL (i.e.: http://example.com/drupal/ instead of
  # http://example.com/), the path to index.php will need to be adjusted.
  &lt;IfModule !mod_rewrite.c&gt;
    FallbackResource /index.php
  &lt;/IfModule&gt;
  
  # Various rewrite rules.
  &lt;IfModule mod_rewrite.c&gt;
    RewriteEngine on
  
    # Set "protossl" to "s" if we were accessed via https://.  This is used later
    # if you enable "www." stripping or enforcement, in order to ensure that
    # you don't bounce between http and https.
    RewriteRule ^ - [E=protossl]
    RewriteCond %{HTTPS} on
    RewriteRule ^ - [E=protossl:s]
  
    # Make sure Authorization HTTP header is available to PHP
    # even when running as CGI or FastCGI.
    # RewriteRule ^ - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
  
    # Block access to "hidden" directories whose names begin with a period. This
    # includes directories used by version control systems such as Subversion or
    # Git to store control files. Files whose names begin with a period, as well
    # as the control files used by CVS, are protected by the FilesMatch directive
    # above.
    #
    # NOTE: This only works when mod_rewrite is loaded. Without mod_rewrite, it is
    # not possible to block access to entire directories from .htaccess because
    # &lt;DirectoryMatch&gt; is not allowed here.
    #
    # If you do not have mod_rewrite installed, you should remove these
    # directories from your webroot or otherwise protect them from being
    # downloaded.
    RewriteRule "/\.|^\.(?!well-known/)" - [F]
  
    # If your site can be accessed both with and without the 'www.' prefix, you
    # can use one of the following settings to redirect users to your preferred
    # URL, either WITH or WITHOUT the 'www.' prefix. Choose ONLY one option:
    #
    # To redirect all users to access the site WITH the 'www.' prefix,
    # (http://example.com/foo will be redirected to http://www.example.com/foo)
    # uncomment the following:
    # RewriteCond %{HTTP_HOST} .
    # RewriteCond %{HTTP_HOST} !^www\. [NC]
    # RewriteRule ^ http%{ENV:protossl}://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
    #
    # To redirect all users to access the site WITHOUT the 'www.' prefix,
    # (http://www.example.com/foo will be redirected to http://example.com/foo)
    # uncomment the following:
    # RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
    # RewriteRule ^ http%{ENV:protossl}://%1%{REQUEST_URI} [L,R=301]
  
    # Modify the RewriteBase if you are using Drupal in a subdirectory or in a
    # VirtualDocumentRoot and the rewrite rules are not working properly.
    # For example if your site is at http://example.com/drupal uncomment and
    # modify the following line:
    # RewriteBase /web
  
    #
    # If your site is running in a VirtualDocumentRoot at http://example.com/,
    # uncomment the following line:
    # RewriteBase /
  
    # Redirect common PHP files to their new locations.
    RewriteCond %{REQUEST_URI} ^(.*)?/(install.php) [OR]
    RewriteCond %{REQUEST_URI} ^(.*)?/(rebuild.php)
    RewriteCond %{REQUEST_URI} !core
    RewriteRule ^ %1/core/%2 [L,QSA,R=301]
  
    # Rewrite install.php during installation to see if mod_rewrite is working
    RewriteRule ^core/install.php core/install.php?rewrite=ok [QSA,L]
  
    # Pass all requests not referring directly to files in the filesystem to
    # index.php.
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_URI} !=/favicon.ico
    RewriteRule ^ index.php [L]
  
    # For security reasons, deny access to other PHP files on public sites.
    # Note: The following URI conditions are not anchored at the start (^),
    # because Drupal may be located in a subdirectory. To further improve
    # security, you can replace '!/' with '!^/'.
    # Allow access to PHP files in /core (like authorize.php or install.php):
    RewriteCond %{REQUEST_URI} !/core/[^/]*\.php$
    # Allow access to test-specific PHP files:
    RewriteCond %{REQUEST_URI} !/core/modules/system/tests/https?.php
    # Allow access to Statistics module's custom front controller.
    # Copy and adapt this rule to directly execute PHP files in contributed or
    # custom modules or to run another PHP application in the same directory.
    RewriteCond %{REQUEST_URI} !/core/modules/statistics/statistics.php$
    # Deny access to any other PHP files that do not match the rules above.
    # Specifically, disallow autoload.php from being served directly.
    RewriteRule "^(.+/.*|autoload)\.php($|/)" - [F]
  
    # Rules to correctly serve gzip compressed CSS and JS files.
    # Requires both mod_rewrite and mod_headers to be enabled.
    &lt;IfModule mod_headers.c&gt;
      # Serve gzip compressed CSS files if they exist and the client accepts gzip.
      RewriteCond %{HTTP:Accept-encoding} gzip
      RewriteCond %{REQUEST_FILENAME}\.gz -s
      RewriteRule ^(.*)\.css $1\.css\.gz [QSA]
  
      # Serve gzip compressed JS files if they exist and the client accepts gzip.
      RewriteCond %{HTTP:Accept-encoding} gzip
      RewriteCond %{REQUEST_FILENAME}\.gz -s
      RewriteRule ^(.*)\.js $1\.js\.gz [QSA]
  
      # Serve correct content types, and prevent mod_deflate double gzip.
      RewriteRule \.css\.gz$ - [T=text/css,E=no-gzip:1]
      RewriteRule \.js\.gz$ - [T=text/javascript,E=no-gzip:1]
  
      &lt;FilesMatch "(\.js\.gz|\.css\.gz)$"&gt;
        # Serve correct encoding type.
        Header set Content-Encoding gzip
        # Force proxies to cache gzipped &amp; non-gzipped css/js files separately.
        Header append Vary Accept-Encoding
      &lt;/FilesMatch&gt;
    &lt;/IfModule&gt;
  &lt;/IfModule&gt;
  
  # Various header fixes.
  &lt;IfModule mod_headers.c&gt;
    # Disable content sniffing, since it's an attack vector.
    Header always set X-Content-Type-Options nosniff
    # Disable Proxy header, since it's an attack vector.
    RequestHeader unset Proxy
  &lt;/IfModule&gt;
  </code></pre>
  
  <p>Or the <code>site.conf</code> file:</p>
  
  <pre><code>&lt;VirtualHost *:80&gt;
  
          ServerName domain.fr
          ServerAlias www.domain.fr
  
          DocumentRoot /var/www/my_project
          &lt;Directory /var/www/my_project&gt;
                  AllowOverride all
                  Order allow,deny
                  allow from all
                  Require all granted
          &lt;/Directory&gt;
  
          ErrorLog ${APACHE_LOG_DIR}/error.log
          CustomLog ${APACHE_LOG_DIR}/access.log combined
  
          RewriteEngine on
          RewriteCond %{SERVER_NAME} =www.domain.fr [OR]
          RewriteCond %{SERVER_NAME} =domain.fr
  &lt;/VirtualHost&gt;
  </code></pre>
  
  <p>At the end of the <code>settings.php</code>, I add: </p>
  
  <pre><code>if (isset($GLOBALS['request']) and
      '/web/index.php' === $GLOBALS['request']-&gt;server-&gt;get('SCRIPT_NAME')) {
          $GLOBALS['request']-&gt;server-&gt;set('SCRIPT_NAME', '/index.php');
  }
  </code></pre>
  
  <p><strong>Note:</strong> </p>
  
  <ul>
  <li>The installation of new module using <code>composer</code> is working.</li>
  <li>I replicated the project on my local machine (Windows) and the installation process is working.</li>
  <li>In the reports logs, after I tried to upload a module through the web interface, there is the following message: </li>
  </ul>
  
  <pre><code>Type        access denied
  Date        Saturday 21 March 2020 - 15:12
  User        Anonymous (not verified)
  Location    http://www.domain.fr/web/core/authorize.php/
  Referrer    http://www.domain.fr/admin/modules/install
  Message     authorize.php
  Importance  Avertissement
  </code></pre>
  
  <ul>
  <li>In the above report, there is the <code>web</code> folder appearing in the location path</li>
  </ul>