403 Forbidden: "CSRF Failed: CSRF token missing." on DRF api-token-auth/ after applying csrf_exempt
I'm encountering a persistent 403 Forbidden error with the detail:
CSRF Failed: CSRF token missing.
This happens when trying to obtain an authentication token using Django REST Framework's built-in api-token-auth/ endpoint.
Context
I am sending a
POSTrequest from Postman (usingrawandapplication/jsonfor the body).The CSRF protection is interfering because Postman, as an external client, doesn't handle session cookies or CSRF tokens.
I attempted to fix this by explicitly applying the
@csrf_exemptdecorator to the view in myurls.py, but the error remains.
Configuration and Code
Here are the relevant snippets from my project setup:
1. settings.py (Middleware and DRF Authentication)
My middleware includes CSRF protection, and I have SessionAuthentication enabled, which seems to be causing the conflict.
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
]
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 10,
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.TokenAuthentication',
'rest_framework.authentication.SessionAuthentication',
),
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
),
}
2. urls.py (Where csrf_exempt is applied)
This is how I'm currently trying to exempt the view. I have imported csrf_exempt from django.views.decorators.csrf.
from django.contrib import admin
from django.urls import path,include
from rest_framework.authtoken import views
from django.views.decorators.csrf import csrf_exempt
from api import views as api_views
urlpatterns = [
path("home/",include("expenses.urls")),
path("admin/", admin.site.urls),
path("api/",include("api.urls")),
path('api-auth/', include('rest_framework.urls')),
path('api-token-auth/', csrf_exempt(views.obtain_auth_token)),
]
Request:
Image of the request that fails in an error
The Question
Why is the csrf_exempt decorator being ignored by the obtain_auth_token view (which is a function-based view in DRF's implementation), even though I'm wrapping it in urls.py?
What is the definitive, robust way to disable CSRF protection only for the api-token-auth/ endpoint when SessionAuthentication is enabled in settings.py?
Note: I need to keep
SessionAuthenticationfor the Browsable API.
When you are using SessionAuthentication, you are using Django's authentication which usually requires CSRF to be checked. Django REST Framework enforces this, only for SessionAuthentication, so you must pass the CSRF token in the X-CSRFToken header.
re : https://stackoverflow.com/a/26639895/16958410
if you want to use session Authentication best practice is to
pass the CSRF token in the X-CSRFToken header
as said in this post
not recommended
if you want SessionAuthentication but do not want to use csrf you can customize SessionAuthentication
example
from rest_framework.authentication import SessionAuthentication
class CsrfExemptSessionAuthentication(SessionAuthentication):
def enforce_csrf(self, request):
return
view
from rest_framework.views import APIView
from rest_framework.permissions import AllowAny
from rest_framework.authtoken.views import ObtainAuthToken
class CustomAuthToken(ObtainAuthToken):
authentication_classes = [CsrfExemptSessionAuthentication]
permission_classes = [AllowAny]
also you can apply it on all project instead of one view like this
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'path.to.CsrfExemptSessionAuthentication'
),
}
read about CSRF [MDN-doc] - [django-doc]