32

I am using the django rest framework to perform API calls via IOS and I get the following error "CSRF Failed: CSRF cookie not set."

Here's my django API code:

class LoginView(APIView):
    """
    List all snippets, or create a new snippet.
    """
    @csrf_exempt
    def get(self, request, format=None):
        startups = Startup.objects.all()
        serializer = StartupSerializer(startups, many=True)
        return Response(serializer.data)

    @csrf_exempt
    def post(self, request, format=None):
        profile = request.POST
....

What can I do?

2
  • Did you ever figure this out? I never got past this. Commented Jul 6, 2013 at 22:07
  • Possible duplicate of Django Rest Framework remove csrf Commented May 26, 2016 at 6:52

8 Answers 8

25

If anyone is still following this question, the direct answer is that you need to use the decorator on the view method itself. The get and post methods defined on the APIView class just tell DRF how the actual view should behave, but the view method that the django router expects is not actually instantiated until you call LoginView.as_view().

Thus, the solution is to add the csrf_exempt decorator to urls.py. It might look as follows:

#file: urls.py

from django.conf.urls import patterns, url
from django.views.decorators.csrf import csrf_exempt

import views

urlpatterns = patterns('',
    url('^login/$', csrf_exempt(views.LoginView.as_view())),
    ...
)

However, as Mark points out above, csrf protection is important to prevent your sessions from being hijacked. I haven't worked with iOS myself, but I would look into using django's cookie-based csrf tokens. You can use the ensure_csrf_cookie decorator to make django send a csrftoken cookie with a response, and your POST requests will validate as long as you include that token as an X-CSRFToken header.

Sign up to request clarification or add additional context in comments.

1 Comment

And how do you do that if your'e using a router?
15

I've had the same issue. My problem was that I forgot to put .as_view() in urls.py on MyAPIView. So it have to be like:

url(r'$', GetLikesAPI.as_view(), name='list')

not:

url(r'$', GetLikesAPI, name='list')

3 Comments

this is unlikely to be the case, since if you miss as_view(), it is likely the route will be inaccessible in total.
This was my case
This was also my case. I was using dot's auth class OAuth2Authentication but APIView's put function was returning Csrf Cookie not Set error. Checked my urls.py and saw I was missing () at the the end of MyAPIView.as_view
8

The problem you encounter here is that django for processing your view is using whatever as_view() method will return, not directly method get() or post().

Therefore you should decorate your class-based view in one of following ways:

  1. In urls.py
    urlpatterns = patterns('',
        url('^login/$', csrf_exempt(views.LoginView.as_view())),
        ...
    )
  1. or on dispatch() method (pre django 1.9)
    from django.utils.decorators import method_decorator

    class LoginView(APIView):
       @method_decorator(csrf_exempt)
       def dispatch(self, *args, **kwargs):
           ...
  1. or on class view itself (from django 1.9)
    from django.utils.decorators import method_decorator


    @method_decorator(csrf_exempt, name='dispatch')
    class LoginView(APIView):
           ...

Comments

4

For GETs, you shouldn't be modifying data, so a CSRF isn't required.

If you are modifying data with a POST, then you SHOULD have a CSRF if you are using session based authentication. Otherwise, you're opening up a security hole. Even though you think your Django server is going to be servicing iPhone apps, there's nothing to stop someone with your app from sniffing the packets on the traffic to your server, and then reverse engineering access to the server with other kinds of web clients. For this reason, Django Rest Framework requires a CSRF in some cases. This is mentioned in the Django rest framework documentation.

The path around this requirement for POSTs is to not use session authentication. For example, you could use BasicAuthentication over HTTPS. With this authentication mechanism, you should use HTTPS to prevent credentials from being passed in the clear with every request.

2 Comments

> our app from sniffing the packets on the traffic - https, so no that's not the reason.
If you're okay with the risk of disabling CSRF because you don't feel that your packets are insecure AND there's no browser involved, you should try the solution from @Rahul Gupta-Iwasaki
3

This is an old question but something we ran into recently.

DRF disables CSRF by default, unless using session authentication. By default NSURLconnection is set up to handle cookies. You need to explicitly tell the iOS app to not use cookies. Then you can keep using session auth if needed and not have to csrf exempt your views.

Comments

3
urlpatterns = patterns('',
       url('^login/$', csrf_exempt(views.LoginView.as_view())),
       ...
)

Guys. I had the same error and spent a lot of time just for finding that: 1) I had another router with 'login' and there i missed '$'. I mean sometimes you can forget something in routing and get this error.

Comments

2

In my case it happend because I sent put request to url='http://example.com/list/5' without slash at the end. When I changed url to url='http://example.com/list/5/' all started to work.

Comments

0

It took a while to find out but i had to just rearrange my urls. I was using Token based authentication but still getting the error until i put the admin site urls at the bottom. Alternatively you could add admin/ to avoid the error

urlpatterns = [
path('api/v1/', include([
    path('client/', include('client.urls')),
]), name="api"),
path('', admin.site.urls, name="admin"),

] In settings.py add this

REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
    'rest_framework.authentication.TokenAuthentication',
),
'DEFAULT_PERMISSION_CLASSES': (
    'rest_framework.permissions.IsAuthenticated',
),
'DEFAULT_RENDERER_CLASSES': [
    'rest_framework.renderers.JSONRenderer',
    'rest_framework.renderers.AdminRenderer',
],
'PAGE_SIZE': 20

}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.