← Back to Django Course | Chapter 7: Django Forms | Lesson 7 of 11

CSRF Protection in Forms

CSRF protection is a secret handshake that makes sure a form submission really came from your own site, not a trick from somewhere else.

Why CSRF Protection Exists

Without it, a malicious site could trick a logged-in user's browser into submitting a form to your app without their knowledge.

Example: Why CSRF Protection Exists

Without it, a malicious site could trick a logged-in user's browser into submitting a form to your app without their knowledge.

markup
<form method="post">
  {% csrf_token %}
  {{ form.as_p }}
  <button type="submit">Save</button>
</form>
{# Django-only code -- models.py/views.py/urls.py/settings.py snippets, or template markup using Django template tags/variables -- can't run standalone via Judge0 or the browser preview, since it needs a real Django project. Only this course's pure-Python examples (example_lang == 'python', no Django imports) are actually runnable, so those still get the button below. #}

What Happens Without the Token

A POST request missing the csrf token is rejected by Django's middleware with a 403 Forbidden response, before your view even runs.

Example: What Happens Without the Token

A POST request missing the csrf token is rejected by Django's middleware with a 403 Forbidden response, before your view even runs.

markup
# settings.py
MIDDLEWARE = [
    # ...
    'django.middleware.csrf.CsrfViewMiddleware',
    # ...
]
{# Django-only code -- models.py/views.py/urls.py/settings.py snippets, or template markup using Django template tags/variables -- can't run standalone via Judge0 or the browser preview, since it needs a real Django project. Only this course's pure-Python examples (example_lang == 'python', no Django imports) are actually runnable, so those still get the button below. #}

CSRF Token in AJAX Requests

For JavaScript-driven POST requests, read the token from the cookie or a hidden input and send it as the X-CSRFToken header.

Example: CSRF Token in AJAX Requests

For JavaScript-driven POST requests, read the token from the cookie or a hidden input and send it as the X-CSRFToken header.

markup
<script>
fetch('/save/', {
  method: 'POST',
  headers: {'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value},
  body: new FormData(document.querySelector('form'))
});
</script>
{# Django-only code -- models.py/views.py/urls.py/settings.py snippets, or template markup using Django template tags/variables -- can't run standalone via Judge0 or the browser preview, since it needs a real Django project. Only this course's pure-Python examples (example_lang == 'python', no Django imports) are actually runnable, so those still get the button below. #}
Common Mistakes
  1. Omitting {% csrf_token %} from a POST form, causing Django to reject the submission with a 403 Forbidden error.
  2. Disabling CSRF protection globally to fix the error instead of adding the missing token tag.
  3. Forgetting that AJAX POST requests also need the CSRF token sent as a header, not just template forms.
Chapter Summary
  • Django's CsrfViewMiddleware rejects POST requests that don't include a valid CSRF token.
  • Every template form that submits via POST must include {% csrf_token %} inside the <form> tag.
  • The token is unique per session, preventing other sites from forging requests to your app.

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.