CSRF Protection

Django blocks cross-site request forgery on every POST form.

Syntax{% csrf_token %}

Django protects you from CSRF (cross-site request forgery) attacks automatically. Every HTML form that uses POST must include the {% csrf_token %} tag, or Django rejects the submission with a 403 error.

The tag renders a hidden field containing a per-session token that Django verifies on the server.

Example

Example Β· python
<form method="post" action="/contact/">
    {% csrf_token %}
    <input type="text" name="name">
    <button type="submit">Submit</button>
</form>

<!-- Forget {% csrf_token %} and Django returns HTTP 403 Forbidden -->

When to use it

  • A developer always adds {% csrf_token %} to POST forms to prevent cross-site request forgery attacks.
  • A developer decorates a view with @csrf_exempt to allow a webhook endpoint to receive POST requests without the token.
  • A JavaScript fetch() call includes the CSRF token from a cookie to make authenticated POST requests to a Django API.

More examples

CSRF token in a form

Adds the {% csrf_token %} tag inside a POST form so Django can verify the request's authenticity.

Example Β· html
<form method="post" action="/submit/">
  {% csrf_token %}
  <input type="text" name="name">
  <button type="submit">Go</button>
</form>

CSRF token in fetch() request

Reads the CSRF token from the cookie and includes it as a request header for AJAX POST calls.

Example Β· javascript
function getCookie(name) {
  const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
  return match ? match[2] : null;
}

fetch('/api/data/', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-CSRFToken': getCookie('csrftoken'),
  },
  body: JSON.stringify({ key: 'value' }),
});

Exempt a webhook view

Disables CSRF checking for a webhook endpoint that receives unsigned POST data from a third party.

Example Β· python
from django.views.decorators.csrf import csrf_exempt
from django.http import HttpResponse

@csrf_exempt
def stripe_webhook(request):
    # Stripe POSTs without a CSRF token; verify with Stripe's signature instead
    payload = request.body
    return HttpResponse(status=200)

Discussion

  • Be the first to comment on this lesson.
CSRF Protection β€” Django | SoundsCode