I found the location.reload()
approach made my SPA (React+Redux front end, DRF backend) look bad/clunky as it would log the user in, then refresh the page (tried using it in different spots but it didn't fix this).
For my situation, both CSRF_USE_SESSIONS and CSRF_COOKIE_HTTPONLY are set to True.
I made the login POST route return a "csrfToken" in the Response payload, and then my authentication reducer, upon processing of the LOGIN_SUCCESS action, would update the hidden csrfmiddlewaretoken input value to the csrfToken so it could then be used for any subsequent requests.
Since you can only get the token if you successfully go through the login route, this should be fine from a security perspective.
template:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Sample</title>
</head>
<body>
<div id="root"></div>
{% load static %}
<script>
// global vars
var CSRF_TOKEN = '{{ csrf_token }}';
</script>
<script src="{% static "frontend/main.js" %}"></script>
</body>
</html>
view:
class LoginAPI(generics.GenericAPIView):
serializer_class = LoginSerializer
def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.validated_data
login(request, user)
return Response({
'csrfToken': get_token(request) # from `django.middleware.csrf`; when called, refreshes the csrf token in the session and returns it
})
reducer:
...
case LOGIN_SUCCESS:
case REGISTER_SUCCESS:
console.log(`old CSRF_TOKEN: ${CSRF_TOKEN}`);
CSRF_TOKEN = action.payload.csrfToken;
return {
...state,
isAuthenticated: true,
isLoading: false
}
...