I'm using Django 3.1.1 with Django's auth contrib module for managing users. I'm not using Django templates, but rather creating a Django API application to respond to requests from my React frontend. I have this in my settings.py file
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'directory.middleware.extend_token_response.ExtendTokenResponse'
]
#CORS_ORIGIN_ALLOW_ALL = True
ALLOWED_HOSTS = ['127.0.0.1', 'localhost', 'dev.mywebsite.com', 'prod.mywebsite.com', 'map.mywebsite.com']
CORS_ORIGIN_WHITELIST = [
'http://localhost:3000', 'http://localhost:3001', 'http://127.0.0.1:3000', 'http://127.0.0.1:3001'
]
CORS_EXPOSE_HEADERS = [
'Refresh-Token', 'Content-Type', 'Authorization', 'X-CSRFToken'
]
CORS_ALLOW_CREDENTIALS = True
CSRF_TRUSTED_ORIGINS = ['localhost', '127.0.0.1']
I have this set up in my views.py file
class ResetPasswordView(SuccessMessageMixin, PasswordResetView):
email_template_name = 'users/password_reset_email.html'
subject_template_name = 'users/password_reset_subject'
success_message = "We've emailed you instructions for setting your password, " \
"if an account exists with the email you entered. You should receive them shortly." \
" If you don't receive an email, " \
"please make sure you've entered the address you registered with, and check your spam folder."
success_url = reverse_lazy('users-home')
def post(self, request, *args, **kwargs):
print("request data %s" % request.data)
email = request.data.get('email')
try:
if User.objects.get(email=email).active:
print("email: %s " % email)
return super(ResetPasswordView, self).post(request, *args, **kwargs)
except:
# this for if the email is not in the db of the system
return super(ResetPasswordView, self).post(request, *args, **kwargs)
In my frontend, I submit password reset requests to my backend using this fetch code
const handleFormSubmit = (e) => {
e.preventDefault()
const csrftoken = getCsrfToken();
fetch(REACT_APP_PROXY + '/reset_password', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'X-CSRFToken': csrftoken
},
body: JSON.stringify({username})
}).then(resp => resp.json())
.then(jsob => {
if(!jsob.ok){
console.log(jsob)
setErrors(jsob)
}
if(jsob.token){
sessionStorage.setItem('token', jsob.token)
setRedirect(true)
}
})
}
The problem is, I don't have a CSRF token the first time I submit the form because Django is not serving my React application (it is served by Apache). How do I get a CSRF token from Django so that I can submit it back during the submission of my password reset form?
Disclaimer
This answer doesn't have an implementation in JS/ReactJS, but it has general instructions on how to have them.
Django will return the CSRF token with the cookies if you access valid views rendered with
TemplateResponse
. To get the CSRF token in your case, you need to send theHTTP GET
request to the same URL (response may look like this). After completing the request, you will have the CSRF token in your cookies' section.Here, I demonstrate a simple example with Python's
requests
library.