Search code examples
djangoauthenticationnginxsingle-page-applicationreverse-proxy

Nginx : How to serve multiple contents with a single internal directive after authentication


I want to display my documentation (a single-page application built with React) only after authentication with my backend.

My configuration :

  • Nginx acts as a reverse proxy for the backend (Django) and serves static files like single-page-applications.
  • Django, the backend, identifies the user and makes a request to Nginx using X-Accel-Redirect.

So I proceed as follows:

1) Authentication on Django

views.py

def get_doc(request):
    if request.method == 'POST':
        form = PasswordForm(request.POST)
        if form.is_valid():
            if form.cleaned_data['password'] == 'foo':
                 response = HttpResponse()
                 response['Content-Type'] = ''
                 response['X-Accel-Redirect'] = '/docs-auth/'
                 return response
            else:
                return HttpResponse("Wrong password")
    else:
        form = PasswordForm()
    return render(request, 'docs/form.html', {'form': form})

urls.py

urlpatterns = [
    path('docs/', views.get_doc, name='documentation'),
]

2) Nginx serves the single-page application

upstream backend {
       server web:8000;
}

server {
       location = /favicon.ico {access_log off;log_not_found off;}

       ...

       location /docs {
         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
         proxy_set_header Host $host;
         proxy_redirect off;
         proxy_pass http://backend;
       }

       location /docs-auth/ {
         internal;
         alias /home/foo/docs/;
         index index.html;
         try_files $uri $uri/ /docs/index.html;   
       }

       location / {
         alias /home/foo/landing_page/;
         error_page 404 /404.html;
         index index.html;
         try_files $uri $uri/ =404;
       }
}

My problem is that the index.html file is served to the user but then the browser requests to access CSS and Javascript files are blocked because the browser cannot access the internal url.

Do you have any ideas to solve my problem?

I am also open to another way to serve a single-page application after backend authentication.

Thanks a lot.


Solution

  • You want to use the auth_request tag to make your life easier. Here is an example that you will need to retrofit unto your config. You could make your whole server require auth my just moving the auth_request tag to the top level outside of location

     server {
       ...
    
       location /docs {
         auth_request     /docs-auth;
    
         ...// Add your file redering here
       }
    
       location = /docs-auth {
            internal;
            proxy_pass              http://auth-server;
            proxy_pass_request_body off;
            proxy_set_header        Content-Length "";
            proxy_set_header        X-Original-URI $request_uri;
       }
     }