2

even though csrf is provided, it just does not recognize it at all in frontend side (note it works perfect on backend, but not frontend)

views.py:

class CheckAuthenticated(views.APIView):
    def get(self, request):
        if request.user.is_authenticated:
            return Response("Authenticated")
        else:
            return Response("Not Authenticated",status=401)
    
class PostView(viewsets.ModelViewSet):
    serializer_class = serializer.PostSerializer

    def get_queryset(self):
        queryset = models.Post.objects.all()
        return queryset
    
    @method_decorator(ensure_csrf_cookie,csrf_protect)
    def create(self,request):
        authentication_classes = [SessionAuthentication]
        permissions_classes = [IsAuthenticated]
        post = serializer.PostSerializer(data=request.data)
        if post.is_valid():
            title = post.data['title']
  
            description = post.data['description']
    
            models.Post.objects.create(title=title,description=description,user=User.objects.first())
            return Response("post created successfully.")
        return Response("post creation failed.")

i have also a resource that receive csrf token:

 
class GetCSRFToken(views.APIView):
    permission_classes = [AllowAny, ]

    
    @method_decorator(ensure_csrf_cookie)
    def get(self, request, format=None):
        return Response("Success")

in urls.py:

  urlpatterns = [
   path('csrf/',views.GetCSRFToken.as_view(),name='csrf'),
   path('isauthenticated/',views.CheckAuthenticated.as_view(),name='authenticated'),
]

now in frontend:

let handleSubmit = (e)=>{
        e.preventDefault()
        console.log(Cookies.get('csrftoken'))
        axios.post('http://127.0.0.1:8000/posts/',post,{withCredentials:true},{headers:{'X-CSRFToken':Cookies.get('csrftoken')}}).then((res)=>{
            console.log(res.data)
        }).catch((e)=>{
            console.log(e.response.data)
            console.log(Cookies.get('csrftoken'))
        })
    }
    useEffect(()=>{
        axios.get('http://127.0.0.1:8000/posts/').then((res)=>{
            setPostList(res.data)
        })
        axios.get('http://127.0.0.1:8000/csrf/',{headers:{Authorization:null},withCredentials:true})

    },[])

the csrf is being printed in the dev console

any idea?

EDIT my csrf settings, since someone requested in the comments:

ALLOWED_HOSTS = ['*']
ACCESS_CONTROL_ALLOW_ORIGIN = '*'
CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_CREDENTIALS = True
ACCESS_CONTROL_ALLOW_CREDENTIALS = True
ACCESS_CONTROL_ALLOW_METHODS = '*'
ACCESS_CONTROL_ALLOW_HEADERS = '*'

'''
SESSION_COOKIE_SECURE = True

CSRF_COOKIE_PATH = '/'
'''
CSRF_COOKIE_SAMESITE = 'Strict'  




CSRF_TRUSTED_ORIGINS = [ "http://127.0.0.1:3000",'http://127.0.0.1:8000']

EDIT : I figured out that in settings.py i have a problem with authentication in drf:

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.SessionAuthentication',
    ]
}

this is what causing the problem, but if i tried to change to like BasicAuthentication i would be unauthorized even if i logged in

I guess this is half the solution, which is finding the problem.

6
  • Could you resolve yor problem? Commented Jun 21, 2022 at 23:02
  • @Jony_23 i did not :/ Commented Jun 21, 2022 at 23:27
  • Please, add your CSRF settings to the question. I think you have an error in create method, this one only have to be decorated with csrf_protect, because with @method_decorator(ensure_csrf_cookie,csrf_protect) you are protecting the view (POST mehod) with CSRF and at the same time it forces to send a new token CSRF. Commented Jun 22, 2022 at 17:18
  • @Jony_23 I added the csrf settings, lemme try your solution Commented Jun 23, 2022 at 1:49
  • alright @Jony_23, so this did not work as you suggested, do you have any other solution? Commented Jun 23, 2022 at 3:08

1 Answer 1

1

After checked your code again, I think I figured out the problem. Your request with axios is incorrect.

axios.post(
            'http://127.0.0.1:8000/posts/',
            post,
            {withCredentials:true},
            {headers:{
                'X-CSRFToken':Cookies.get('csrftoken')}}
).then((res)=>{
            ...

Now check the Axios API.

axios.post(url[, data[, config]])

If match one by one.

url - 'http://127.0.0.1:8000/posts/'

data - post (I guess this is the variable where data are saved, I suggest you rename it)

config - {withCredentials:true}

Until I understand your cookie is sent (due to withCredentials:true), but your header not. They are ignored by axios.

So, you have to put all the configuration in the same object. For example using a variable:

const postRequestConf = {
    withCredentials: true,
    headers: {
        'X-CSRFToken': Cookies.get('csrftoken')
    }
}

If you want, you can add xsrfHeaderName: 'X-CSRFToken' and xsrfCookieName: 'csrftoken' to the object. Check Request Config.

And the request.

axios.post(
           'http://127.0.0.1:8000/posts/',
           renamedVariable,
           postRequestConf
).then( res => {...})...

Now, the request must be sent this data. You can verify it in DevTools > Network.

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

1 Comment

New versions of axios needs to add withXSRFToken = true stackoverflow.com/a/77520347/8564512

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.