# Forbidden: Origin checking failed does not match trusted origins django

## TL;DR

The request's Origin header is not in CSRF_TRUSTED_ORIGINS, so Django rejected the POST. Add the exact origin (scheme plus host, and port if nonstandard) to the setting. This fires on HTTPS deployments behind proxies where the origin differs from what Django expects.

```text
Forbidden (403)
Origin checking failed - https://app.example.com does not match any trusted origins.
```

## Steps

1. Read the failing Origin from the 403 page or logs.
   Expected: You have the exact origin string.

2. Add it verbatim to CSRF_TRUSTED_ORIGINS, including the scheme and any nonstandard port.
   Expected: The setting lists the origin.

3. Check for proxy mangling: if Django sees http while the browser sees https, set SECURE_PROXY_SSL_HEADER so the scheme matches.
   Expected: The origin Django computes matches the browser's.

4. Restart (or reload) so the setting takes effect, then retry the POST.
   Expected: The 403 clears.

5. Audit the list periodically; stale origins are a widening hole.
   Expected: Only real origins are trusted.

## When to use

- Django 403s with 'Origin checking failed'
- the app sits behind a proxy or on a nonstandard port
- cross-subdomain POSTs fail

## When not to use

- the message is the generic CSRF failure (different fix)
- the origin is genuinely untrusted (then the 403 is correct)
- CSRF_TRUSTED_ORIGINS is already correct (check the proxy scheme instead)

## Tool compatibility

- Django 3.2 through 5.x
- proxy deployments

## Variant phrasings

- "django origin checking failed trusted origins"
- "CSRF_TRUSTED_ORIGINS django"
- "forbidden origin checking failed django"

## Why it happens

Django 4+ checks the Origin header against CSRF_TRUSTED_ORIGINS for HTTPS POSTs. Behind a TLS-terminating proxy, Django may compute the wrong origin (http vs https) or the deployment simply never listed the frontend's origin. The check is exact-string, so scheme, host, and port must all match.

## Edge cases

- wildcard subdomains are not allowed; list each origin explicitly
- the setting needs the public origin, not the internal container address
- changing SECURE_PROXY_SSL_HEADER has security implications; only trust your own proxy

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_vfc6vLTCRCwNyftgGn8-cg
