How to authorize static files in Laravel with Nginx auth_request

Published at: 2020-07-26 21:29:00

When it is necessary to authenticate and authorize the access of static files, such as downloadable content, images etc, the common approach is to read the file with PHP and return the content. Laravel’s download method also works this way. There is nothing wrong with this approach. However it could lead to some performance issues if there is a high load on the server, or when serving big files.

Using Nginx http_auth_request_module

If you use Nginx built with the http_auth_request_module you can utilize the auth_request directive to create authentication based on subrequest result.

As the official documentation says:

To perform authentication, NGINX makes an HTTP subrequest to an external server where the subrequest is verified. If the subrequest returns a 2xx response code, the access is allowed, if it returns 401 or 403, the access is denied. 

You can see the basic principle on the following diagram:

As an example we will create a downloads section and protect it with the auth_request and authenticate against the Laravel users table. So let’s create a location within the nginx config, and set up the auth_request:

location /downloads {
    auth_request     /auth;
    auth_request_set $auth_status $upstream_status;

Create the /auth internal location which will basically proxy the subrequest to the authentication service, which can be an internal location or and external url (an SSO server for example) :

location = /auth {
    proxy_pass              http://my-shop.test/authenticate;
    proxy_pass_request_body off;
    proxy_set_header        Content-Length "";
    proxy_set_header        X-Original-URI $request_uri;

Passing the original request uri can help in authorization. Using the X-Original-URI header we could determine if the user has access to the given url.

Let’s create a route and handle the auhentication part. In this example will use the simplest approach and utilize the Laravel’s built in basic.auth middleware:

Route::get('/authenticate', function () {
    // Use the $originalUri to authorize the request if necessary
    $originalUri = request()->header('X-Original-URI');

    return '';

Thats it. We have a working authentication for the /downloads location. By default the middleware authenticates against the users table, where the email field would be used as the username. Of course you can use other authentication methods and customize the authorization as well. The original uri can be retrieved from the request headers like this:

$originalUri = request()->header('X-Original-URI');

For me it is pretty interesting and useful Nginx feature, hope it was also interesting for you. If you liked the article check out my other tech related blog posts.