How can I disable Django's csrf protection only in certain cases?
Asked Answered
K

4

44

I'm trying to write a site in Django where the API URLs are the same as user-facing URLs. But I'm having trouble with pages which use POST requests and CSRF protection. For example, if I have a page /foo/add I want to be able to send POST requests to it in two ways:

  1. As an end user (authenticated using a session cookie) submitting a form. This requires CSRF protection.
  2. As an API client (authenticated using a HTTP request header). This will fail if CSRF protection is enabled.

I have found various ways of disabling CSRF, such as @csrf_exempt, but these all disable it for the entire view. Is there any way of enabling/disabling it at a more fine-grained level? Or am I just going to have to implement by own CSRF protection from scratch?

Karleen answered 7/7, 2012 at 10:56 Comment(2)
Did you check csrf protection docs?Cirillo
I'd had read bits of it, but clearly didn't read all the Scenarios. Thanks!Karleen
S
34

There is a section of Django's CSRF Protection documentation titled View needs protection for one path which describes a solution. The idea is to use @csrf_exempt on the whole view, but when the API client header is not present or invalid, then call a function annotated with @csrf_protect.

Stagg answered 7/7, 2012 at 11:33 Comment(0)
C
71

Modify urls.py

If you manage your routes in urls.py, you can wrap your desired routes with csrf_exempt() to exclude them from the CSRF verification middleware.

for instance,

from django.views.decorators.csrf import csrf_exempt
urlpatterns = patterns(
    # ...
    # Will exclude `/api/v1/test` from CSRF 
    url(r'^api/v1/test', csrf_exempt(TestApiHandler.as_view()))
    # ...
)

Alternatively, as a Decorator

Some may find the use of the @csrf_exempt decorator more suitable for their needs

for instance,

from django.views.decorators.csrf import csrf_exempt
from django.http import HttpResponse

@csrf_exempt
def my_view(request):
    return HttpResponse('Hello world')
Corticate answered 30/6, 2015 at 10:40 Comment(0)
S
34

There is a section of Django's CSRF Protection documentation titled View needs protection for one path which describes a solution. The idea is to use @csrf_exempt on the whole view, but when the API client header is not present or invalid, then call a function annotated with @csrf_protect.

Stagg answered 7/7, 2012 at 11:33 Comment(0)
P
8

If you are you using class base view (CBV) and want to use the csrf_exempt decorator you will need to use the method decorator.

from django.utils.decorators import method_decorator
from django.views import View
from django.views.decorators.csrf import csrf_exempt

@method_decorator(csrf_exempt, name='dispatch')
class MyView(View):
    def post(self, request):
        pass  # my view code here
Pseudohermaphroditism answered 18/12, 2019 at 9:33 Comment(1)
Are you sure of this solution?Suwannee
C
2

In my case, I am using JWT authentication plus csrf_token for some views. And for some reasons that I am unaware of, csrf_exempt does not work when I set it as a decorator or when I wrap the view name in the url patterns.

So here's what I ended up doing. I overrided the initialize_request available in the APIView class.

class ClasssName(views.APIView):
    def initialize_request(self, request, *args, **kwargs):
        setattr(request, 'csrf_processing_done', True) 
        return super().initialize_request(request, *args, **kwargs)
Curtain answered 18/12, 2021 at 1:47 Comment(1)
For me this is the only thing that worked when getting the error: CSRF Failed: CSRF cookie not set. This happens when trying to post data from a Vue frontend in dev mode. Both the Django and Vue frontend are running on localhost but on different ports. The CSRF token was send through http headers but still got the cookie message. The csrf_exempt decorator did not work (even though it is one of my answers on another SO question). Custom middleware also did not do the trick. This finally works to bypass the cookie error.Prisoner

© 2022 - 2024 — McMap. All rights reserved.