Django rest framework gives 403 when behind nginx, but not directly

Using django-rest-framework. I get HTTP 403 errors when starting in production for nginx. When I call a specific view that inherits from APIView to support the GET operation, I get:

{"detail": "Invalid username/password"} 

But ... I only get this in the browser. I do not get it when I use curl for the same url. I get this error whether I get directly to the URL or load the URL through AJAX, in both Chrome and Firefox.

I do not get an error if I log in through Django Admin with an administrator account.

Also, I only get this, I am running because of nginx. If I start the Django dev or gunicorn server and directly go to the port, I am fine and can happily use the URL anonymously. If I then put nginx in front of this to forward the same action / server start, I get this error.

Maybe this has something to do with the settings of my nginx proxy_pass?

 location / { proxy_pass http://127.0.0.1:8000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } 

I am running django rest framework 2.2.6, Django 1.5 and nginx 1.2.7.

I set throttling to a stupid large number in the rest structure and looked at permissions that all seemed to be open by default (but also set so explicitly).

Can someone point me in the right direction?

Thanks!

Ludo.

+6
source share
4 answers

You will get 403 FORBIDDEN if you have throttling on. Based on this question: https://github.com/tomchristie/django-rest-framework/issues/667 , disabling the lazy rating of request.user / request.auth is probably best.

0
source

In my case, I had basic HTTP authentication configured in Apache, but not in my Django project. Since the request had authentication headers, the Django application thought I wanted to authenticate. I disabled authentication in the Django REST framework using the following settings:

 REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': [] } 
+23
source

If this is the main HTTP authenticator (as is the case with @Sjoerd) and you don't need django authentication, you can also remove the Authorization header in your nginx reverse proxy configuration:

 location / { ... proxy_set_header Authorization ""; } 
+3
source

When you send a request to the site that is behind basic authentication, the client (browser) sends the "Authorization" header (as follows - see "Basic access authentication" on Wikipedia).

Ngnix passes it to your application.

Django Rest Framework also supports: BasicAuthentication, and it is enabled by default.

 REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework.authentication.BasicAuthentication', 'rest_framework.authentication.SessionAuthentication', ) } 

source: http://www.django-rest-framework.org/api-guide/authentication/

So, django-rest-framework sees the "Authorization" heading and thinks that it should be a django user with a password.

If such a user does not exist, you have received: "HTTP 401 Unauthorized". See: http://www.django-rest-framework.org/api-guide/authentication/#basicauthentication

Soultions

Choose one: a) Add ngnix to your site configuration

 location / { ... proxy_set_header Authorization ""; ... } 

therefore, DRF will not get the "Authorization" header, so it will not try to map the django user.

After this change - basic auth cannot be used on the django side (empty header!

b) Get rid of "rest_framework.authentication.BasicAuthentication" from REST_FRAMEWORK (in django settings).

If not defined, add django settings:

 REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework.authentication.SessionAuthentication', ) } 

Probably the best solution.

c) Use your django user / password for basic auth?

Realy? - Do not!

+2
source

All Articles