How to set up csrf token with Django and React

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:

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)
})