I am working on a Django backend to handle some data manipulation, specifically appending and deleting data. My code works perfectly when tested with Postman, but I encounter a 403 Forbidden error when trying to access the /bookings/remove/ endpoint from my React Native frontend.
Here’s the error message I receive: Forbidden (CSRF token missing.): /bookings/remove/ "POST /bookings/remove/?booking_id=148/ HTTP/1.1" 403
Interestingly, all other endpoints are working fine without any CSRF-related issues. It’s only this specific endpoint that is causing problems.
Django Backend
i have my settings for cors as follows:
INSTALLED_APPS = [
'corsheaders',
"all other apps"
]
SESSION_COOKIE_SECURE = False
SESSION_COOKIE_SAMESITE = None
SESSION_COOKIE_AGE = 1209600
CORS_ALLOW_ALL_ORIGINS = True
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.security.SecurityMiddleware',
'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_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.TokenAuthentication',
'rest_framework_simplejwt.authentication.JWTAuthentication',
],
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 10,
}
and my endpoint for which i am getting error is
@api_view(["POST"])
@permission_classes([IsAuthenticated])
@csrf_exempt
def cancel_the_booking(request, booking_id):
try:
if not booking_id:
return Response({"error": "Booking ID is required"}, status=status.HTTP_400_BAD_REQUEST)
booking = Booking.objects.get(booking_id=booking_id)
if booking.host_id != request.user.id:
return Response({"error": "You are not authorized to cancel this booking", "host": request.user.id}, status=status.HTTP_403_FORBIDDEN)
for date_price in booking.dates_price.all():
AdSpaceDates.objects.create(
ad_space=booking.space_id,
available_from=date_price.available_from,
available_to=date_price.available_to,
price=date_price.price
)
booking.delete()
return Response({"success": "Booking cancelled and dates are now available again"}, status=status.HTTP_200_OK)
except Booking.DoesNotExist:
return Response({"error": "Booking does not exist"}, status=status.HTTP_404_NOT_FOUND)
except Exception as e:
return Response({"error": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
my urls.py for Booking app
path('remove/<int:booking_id>/', cancel_the_booking , name="cancel_the_booking")
and my project urls.py is
path("bookings/", include("Bookings.urls")),
to retrive the csrf
@api_view(["GET"])
@ensure_csrf_cookie
def get_csrf_token(request):
csrf_token = get_token(request)
return JsonResponse({'csrfToken': csrf_token})
path('api/get-csrf-token/', get_csrf_token, name='get_csrf_token'),
React Native code
const getCsrfToken = async () => {
try {
const response = await Api.get('/api/get-csrf-token/');
return response.data.csrfToken;
} catch (error) {
console.error('Error fetching CSRF token', error);
return null;
}
};
const handleConfirmButton = (booking) => {
Alert.alert(
'Cancel Booking',
'Are you sure you want to cancel this booking?',
[
{
text: 'No',
onPress: () => console.log('Cancel Pressed'),
style: 'cancel',
},
{
text: 'Yes',
onPress: () => handleBookingCancellation(booking),
},
],
{ cancelable: false }
);
};
const handleBookingCancellation = async (booking) => {
try {
const csrfToken = await getCsrfToken();
if (!csrfToken) {
Alert.alert('Error', 'Failed to fetch CSRF token');
return;
}
const response = await axios.post(`http://127.0.0.1:8000/bookings/remove/?booking_id=${booking.booking_id}/`, {
headers: {
'Authorization': `Bearer ${await SecureStore.getItemAsync('access')}`,
'X-CSRFToken': csrfToken
},
});
Alert.alert("Booking Cancelled", `Booking ID: ${booking.booking_id}`);
console.log(response);
} catch (error) {
console.error('Error cancelling booking', error);
Alert.alert('Error', 'There was an error cancelling the booking');
}
};
<TouchableOpacity style={styles.confirmButton } onPress={() => handleConfirmButton(item)} >
<Text style={styles.viewAllText}>Cancel Booking</Text>
<AntDesign name="delete" size={24} color="white" style={styles.icon} />
</TouchableOpacity>
I have tried multiple approaches to resolve the 403 Forbidden (CSRF token missing) error specifically for the /bookings/remove/ endpoint:
- Fetching the CSRF Token:
Implemented a CSRF token fetch from the backend using a dedicated endpoint (/api/get-csrf-token/). The token fetch works correctly and returns a valid CSRF token.
- Sending the CSRF Token in Requests:
Modified the fetch request in React Native to include the CSRF token in the headers. Expected the backend to accept the request and process the booking cancellation.
- Adjusting Django Settings:
Ensured CSRF_TRUSTED_ORIGINS and CORS_ALLOWED_ORIGINS include the frontend URLs. Enabled CORS_ALLOW_ALL_ORIGINS.
- Changing HTTP Method and Headers:
Tried using both POST and DELETE methods. Included necessary headers (Authorization, Content-Type, and X-CSRFToken).
Despite these efforts, the request to /bookings/remove/ consistently results in a 403 Forbidden (CSRF token missing) error. Other endpoints are functioning correctly without this issue, which is confusing.
I was expecting the request to succeed, cancel the booking, and return a confirmation response, but it fails at the CSRF validation stage.
I expected that after correctly fetching and including the CSRF token in the request headers, the backend would validate the token and allow the booking cancellation request to proceed without returning a 403 Forbidden error.
while everything working fine with postman.