htaccess exclude one url from Basic Auth

Using SetEnvIf, you can create a variable when the request starts with some path, then use the Satisfy Any directive to avoid having to login.

# set an environtment variable "noauth" if the request starts with "/callbacks/"
SetEnvIf Request_URI ^/callbacks/ noauth=1

# the auth block
AuthName "Please login."
AuthGroupFile /dev/null
AuthType Basic
AuthUserFile /xxx/.htpasswd

# Here is where we allow/deny
Order Deny,Allow
Satisfy any
Deny from all
Require valid-user
Allow from env=noauth

The allow/deny chunk of directives says that deny access for EVERYONE, except when there is a valid-user (successful BASIC auth login) or if the noauth variable is set.


If you are using Apache 2.4, SetEnvIf and mod_rewrite workarounds are no longer necessary since the Require directive is able to interpret expressions directly:

AuthType Basic
AuthName "Please login."
AuthUserFile "/xxx/.htpasswd"

Require expr %{REQUEST_URI} =~ m#^/callbacks/.*#
Require valid-user

Apache 2.4 treats Require directives that are not grouped by <RequireAll> as if they were in a <RequireAny>, which behaves as an "or" statement. Here's a more complicated example that demonstrates matching both the request URI and the query string together, and falling back on requiring a valid user:

AuthType Basic
AuthName "Please login."
AuthUserFile "/xxx/.htpasswd"

<RequireAny>
    <RequireAll>
        # I'm using the alternate matching form here so I don't have
        # to escape the /'s in the URL.
        Require expr %{REQUEST_URI} =~ m#^/callbacks/.*#

        # You can also match on the query string, which is more
        # convenient than SetEnvIf.
        #Require expr %{QUERY_STRING} = 'secret_var=42'
    </RequireAll>

    Require valid-user
</RequireAny>

This example would allow access to /callbacks/foo?secret_var=42 but require a username and password for /callbacks/foo.

Remember that unless you use <RequireAll>, Apache will attempt to match each Require in order so think about which conditions you want to allow first.

The reference for the Require directive is here: https://httpd.apache.org/docs/2.4/mod/mod_authz_core.html#require

And the expression reference is here: https://httpd.apache.org/docs/2.4/expr.html


This solution works pretty well, you just need to define whitelist you want to pass through.

SetEnvIfNoCase Request_URI "^/status\.php" noauth

AuthType Basic
AuthName "Identify yourself"
AuthUserFile /path/to/.htpasswd
Require valid-user

Order Deny,Allow
Deny from all
Allow from env=noauth

Satisfy any

I tried the other solutions but this is what worked for me. Hopefully it will be of help to others.

# Auth stuff
AuthName "Authorized personnel only."
AuthType Basic
AuthUserFile /path/to/your/htpasswd/file

SetEnvIf Request_URI "^/index.php/api/*" allow
Order allow,deny
Require valid-user
Allow from env=allow
Deny from env=!allow
Satisfy any

This will allow the api url and any url string after /index.php/api/ to open without having to login and anything else will be prompted to login.

Example:

mywebsite.com/index.php/api will open without being prompted to login mywebsite.com/index.php/api/soap/?wsdl=1 will open without being prompted to login mywebsite.com will be prompted to login first