Repository: paperless-ngx/paperless-ngx

Issue:
[BUG] Forbidden (403) CSRF verification failed.
### Description

I have `dev` version of paperless open to the internet, so I can play around with translations and mobile apps while on the go. For the last few days I have found that I cannot log in any more I get the error pictured below:
![image](https://user-images.githubusercontent.com/5058121/162325688-8913f212-cc07-460a-b7e4-fa5a3c6e81b3.png)



### Expected behavior

Getting logged in into the website

### Steps to reproduce

1. login
2. get error

### Webserver logs

```bash
[2022-04-07 23:49:57,265] [WARNING] [django.security.csrf] Forbidden (Origin checking failed - https://paperlessdev.xxxxxxxx.org does not match any trusted origins.): /accounts/login/
```


### Screenshots

_No response_

### Paperless-ngx version

1.6.0 dev

### Host OS

Linux/Unraid

### Installation method

Docker

### Browser

chrome

### Configuration changes

/

### Other

There were changes in how django works in 4.0.0+. 


Discussion:
Hmm, have you tried https://stackoverflow.com/a/70326426/5331804 , does that solve it?
So i added CSRF_TRUSTED_ORIGINS = ['https://paperlessdev.mydomain.com'] and it started working.... sorry for late reply i had to figure how to add it :D
Thanks for confirming. Presumably this will be an issue for all users in the next version and would probably warrant a (yep) new environment variable especially from docker eg `PAPERLESS_URL`? Unless I’m misunderstanding something. I can take a look later (unless someone gets to it first ofc)
Yes, a new variable will be needed. Origin is checked from django 4.0+
![image](https://user-images.githubusercontent.com/5058121/162333474-ae4bb32e-0e73-4f2d-ad45-c8596a039c82.png)

@paperless-ngx/backend we already have `PAPERLESS_ALLOWED_HOSTS` (which came from https://github.com/the-paperless-project/paperless/issues/172) as well as `PAPERLESS_CORS_ALLOWED_HOSTS`. What do we think best practice is here? Leave those alone and just create something like `PAPERLESS_URL` that supersedes the others? 

Feels like too many though they do do different things. The following are core Django settings (`CSRF...` isnt):

- https://docs.djangoproject.com/en/4.0/ref/settings/#allowed-hosts
- https://docs.djangoproject.com/en/4.0/ref/settings/#csrf-trusted-origins

Maybe we just use `PAPERLESS_URL` and the others can be derived from that unless they are also specified? Any issues with that?

Resolving patch:
diff --git a/src/paperless/settings.py b/src/paperless/settings.py
--- a/src/paperless/settings.py
+++ b/src/paperless/settings.py
@@ -4,6 +4,7 @@
 import os
 import re
 from typing import Final
+from urllib.parse import urlparse
 
 from concurrent_log_handler.queue import setup_logging_queues
 from django.utils.translation import gettext_lazy as _
@@ -219,7 +220,15 @@ def __get_int(key: str, default: int) -> int:
 else:
     X_FRAME_OPTIONS = "SAMEORIGIN"
 
-# We allow CORS from localhost:8080
+
+# The next 3 settings can also be set using just PAPERLESS_URL
+_csrf_origins = os.getenv("PAPERLESS_CSRF_TRUSTED_ORIGINS")
+if _csrf_origins:
+    CSRF_TRUSTED_ORIGINS = _csrf_origins.split(",")
+else:
+    CSRF_TRUSTED_ORIGINS = []
+
+# We allow CORS from localhost:8000
 CORS_ALLOWED_ORIGINS = tuple(
     os.getenv("PAPERLESS_CORS_ALLOWED_HOSTS", "http://localhost:8000").split(","),
 )
@@ -228,6 +237,22 @@ def __get_int(key: str, default: int) -> int:
     # Allow access from the angular development server during debugging
     CORS_ALLOWED_ORIGINS += ("http://localhost:4200",)
 
+_allowed_hosts = os.getenv("PAPERLESS_ALLOWED_HOSTS")
+if _allowed_hosts:
+    ALLOWED_HOSTS = _allowed_hosts.split(",")
+else:
+    ALLOWED_HOSTS = ["*"]
+
+_paperless_url = os.getenv("PAPERLESS_URL")
+if _paperless_url:
+    _paperless_uri = urlparse(_paperless_url)
+    CSRF_TRUSTED_ORIGINS.append(_paperless_url)
+    CORS_ALLOWED_ORIGINS += (_paperless_url,)
+    if _allowed_hosts:
+        ALLOWED_HOSTS.append(_paperless_uri.hostname)
+    else:
+        ALLOWED_HOSTS = [_paperless_uri.hostname]
+
 # The secret key has a default that should be fine so long as you're hosting
 # Paperless on a closed network.  However, if you're putting this anywhere
 # public, you should change the key to something unique and verbose.
@@ -236,12 +261,6 @@ def __get_int(key: str, default: int) -> int:
     "e11fl1oa-*ytql8p)(06fbj4ukrlo+n7k&q5+$1md7i+mge=ee",
 )
 
-_allowed_hosts = os.getenv("PAPERLESS_ALLOWED_HOSTS")
-if _allowed_hosts:
-    ALLOWED_HOSTS = _allowed_hosts.split(",")
-else:
-    ALLOWED_HOSTS = ["*"]
-
 AUTH_PASSWORD_VALIDATORS = [
     {
         "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",


Test patch: