I read in the docs that DRF only validates CSRF tokens on authenticated requests and login views should explicitely check the CSRF token.
Problem is, how does one manually check the CSRF token?
In my settings.py
:
MIDDLEWARE = [
...
"django.middleware.csrf.CsrfViewMiddleware",
...
]
Here’s my view:
from rest_framework.decorators import api_view
from django.http import JsonResponse
from django.views.decorators.csrf import get_token
# I have to manually generate the csrf token and put it in the response body, because I use react-native and that can't read the token from the 'Set-Cookie' header
@api_view(["GET"])
def user_info(request):
return JsonResponse({"csrf_token": get_token(request)})
@api_view(["POST"])
def login(request):
return JsonResponse({"foo": "bar"})
When I make a POST request in the frontend and I don’t provide the CSRF token, it should fail, but I actually receive the {"foo": "bar"}
JSON.
I tried the @csrf_protect
and @requires_csrf_token
decorators, but the request is still not failing.
I also tried this, but that errors on required positional argument: 'get_response
CsrfViewMiddleware().process_view(request, None, (), {})
If I pass a function to get_response
, that function is never called:
def test_get_response(req):
breakpoint()
CsrfViewMiddleware(get_response=test_get_response).process_request(request)
I checked that the CSRF token is not passed in the headers, not the cookies, and I tried different browsers and incognito mode.
How do I get my api requests to fail if they don’t include a valid CSRF token?
2
Answers
Okay... a few rabbit holes later, I found some kind of solution.
Django uses
Double Submit Cookie
for CSRF validation. This means:Set-Cookie
headerProblem is, React Native doesn't support cookies, so it has to send the CSRF token some other way. Problem with that is there is not way to do that securely.
I solved it by writing custom middleware for django:
Bit cumbersome, but I only have to validate this way on web requests.
You’re having error in this importing
from django.views.decorators.csrf import get_token
. you should importget_token
fromdjango.middleware.csrf
.according to django documentation and it return the CSRF token required for a POST form.