WEBcoast Logo

Apache + mod_rewrite: Exclude certain paths from basic authentication

Sometimes it's necessary to protect a website or -application with basic authentication, but leave certain urls publicly available. There are many examples which either use the <Location> directive or do not use mod_rewrite. But you cannot build a modern web-application without mod_rewrite. In some cases it is necessary or could be useful to place the basic authentication settings in an .htaccess file instead of the server/vhost configuration, which means, that the <Location> directive could not be used.

Though the combination of basic authentication and mod_rewrite is kind of special, because the Apache applies the authentication rules twice. First for the primary request, where the variable REQUEST_URI contains the url requested from the client and thereafter for the internal subrequest after the rewrite rules has been applied. If you rewrite all urls that does not match a file, a link or a directory to index.php, the subrequest will have /index.php as REQUEST_URI. In our case that lead to, that the granted access for the directory worked for the primary request, but not for the internal subrequest. We solved this as follows: 

# Active rewrite engine
RewriteEngine On
# Set environment variable using rewrite for the desired url
# Attention: The url does not start with a "/" here
# Do not add the [L] flag to allow further processing of rewrite rules
RewriteRule ^the-url/you-want/to-match/.*$ - [E=MATCH_DOWNLOAD_URL:1]
# The normal rewrites for our application
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^.*$ index.php [NC,L]
# Activate basic authentication
AuthType Basic
AuthName "Please login"
AuthUserFile /absolute/path/to/.htpasswd
# Grant access to the desired url (matches in the primary request)
Require expr %{REQUEST_URI} =~ m#^/the-url/you-want/to-match/.*$#
# Grant access, if the environment variable is set (matches in the subrequest)
Require env REDIRECT_MATCH_DOWNLOAD_URL
# Otherwise ask for username and password
Require valid-user

The Require directives behave as they were grouped by <RequireAny> meaning one condition must be satisfied to make the request authenticated.