How to set up csrf token with Django and React
using axios and django-cors-headers
I'm not sure that this implementation is completely correct from a security point, but i want write this article because i found some problems to set up django and react using the csrf.
I'm using:
- Django 4.0
- React 17
- django-cors-headers
- axios
This is my set up for the file setting.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'corsheaders', //<------cors
'api'
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'corsheaders.middleware.CorsMiddleware', //<------cors
'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',
]
CORS_ALLOW_CREDENTIALS = True
CORS_ALLOWED_ORIGINS=["http://localhost:3000", "http://127.0.0.1:3000"]
CSRF_TRUSTED_ORIGINS = ["http://localhost:3000", "http://127.0.0.1:3000"]
This is my view to get the csrf token, with the decorator ensure_csrf_cookie, a set-cookie will be added in the http response so we will found our csrftoken cookie in the browser
from django.views.decorators.csrf import ensure_csrf_cookie
@ensure_csrf_cookie
def get_csrf(request):
return JsonResponse({})
For the frontend its important to call our view before our request to get the token, if the token is alredy present will be updated the expiration time.
const get_csrf = () => axios.get('http://localhost:8000/api/get_csrf').then(res => {})
After we have the cookie we can execute our POSTs
axios.defaults.xsrfCookieName = 'csrftoken'
axios.defaults.xsrfHeaderName = 'X-CSRFToken'
axios.defaults.withCredentials = true
axios.post('http://localhost:8000/api/upload_data', { 'test': 'ok' }).then(res => {
console.log(res)
}).catch(err => {
console.log(err)
})
axios.defaults.xsrfCookieName = 'csrftoken'
axios.defaults.xsrfHeaderName = 'X-CSRFToken'
will setup automatically the header for you (for every request) if you want do it manually you can get the csrf token in this way
// from django website https://docs.djangoproject.com/en/4.0/ref/csrf/
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
const csrftoken = getCookie('csrftoken');
or using this library
- npm i js-cookie
- npm i @types/js-cookie (if you are using typescript)
and set manually the header of the http post request
const csrftoken = Cookies.get('csrftoken')
axios.post('http://localhost:8000/api/upload_data',
{ 'body_data': 'ok' },
{ headers: { 'X-CSRFToken': csrftoken }}
).then(res => {
console.log(res)
}).catch(err => {
console.log(err)
})