This works fine for the most part. However I’ve noticed in the desktop (in the cloud file browser) and mobile app, no thumbnails are shown, instead this error is printed in the Seahub log: django.request:253 log_response Forbidden: /api2/repos/XXXXX/thumbnail/
When accessed via the WebUI, the thumbnails work fine. My tcpdump shows that the web ui always sends the x-csrftoken header and includes it also in the cookie:
However the apps do not send any of these headers, instead only an auth token is sent: authorization: Token XXXX
This causes Seahub to deny the request. All other X-Forwarded-Host and X-Forwarded-Proto headers are present. Apart from the thumbnails the mobile app and desktop app work fine.
If I remove CSRF_TRUSTED_ORIGINS, the WebUI stops working correctly. Requests to create new files or delete files will fail with “permission denied” and a similar log entry: django.request:253 log_response Forbidden: /api/v2.1/repos/XXXXXX/file/
It could be that the issue is not related to CSRF, but the missing header/cookie and the really similar error indicated to me that they might be related.
As an additional note, I use my own nginx config since the included one is not customizable and unnecessary if you already have another reverse proxy. This is the location directive:
As far as I know, APIs don’t use CSRF and cookie. Here is my discussion with AI:
You’ve raised an excellent point. In a typical modern architecture, APIs that use token-based authentication (like the Authorization: Token... header you’re seeing) are indeed stateless and should not be subject to CSRF protection, which is designed for cookie-based browser sessions.
However, the situation with Seafile is a bit more nuanced. Here’s my thinking based on the new information:
The core of the issue is that Seafile’s web interface (Seahub) and its internal APIs are both handled by the same backend framework: Django. As of Seafile 11 (you are using 13), the underlying Django framework was upgraded, which introduced stricter CSRF checks.
Here’s a breakdown of what’s likely happening:
Stricter Django CSRF Rules: Newer versions of Django don’t just look for a CSRF token; they also verify that the Origin or Referer header of the request matches the host it’s being served from. This is a security enhancement to prevent cross-site attacks. When you correctly set CSRF_TRUSTED_ORIGINS = ['https://seafile.example.com'], you are telling Django that it’s safe to accept requests originating from your domain.
Web UI vs. Client Apps:
Web UI: When you use your browser, it correctly sends an Origin header (e.g., https://seafile.example.com). This matches your CSRF_TRUSTED_ORIGINS setting, and everything works as expected.
Mobile/Desktop Apps: The client applications, as you noted, authenticate with a token. They are not operating within a browser session and likely do not send an Origin header with their requests.
The Conflict: When the request from the app hits the /api2/repos/XXXXX/thumbnail/ endpoint, Django’s CSRF middleware inspects it. It sees a request that should be protected but finds no Origin header to validate against your CSRF_TRUSTED_ORIGINS list. Because of the stricter rules, the absence of this header for a protected endpoint leads to an immediate “403 Forbidden” rejection.
So, you are correct that the API call itself isn’t using CSRF for its logic. The problem is that the API endpoint is getting caught in the web UI’s CSRF protection net. The authentication token is valid, but the request is being blocked by the CSRF middleware before it can even be processed.
In summary, your thinking is right from an API design perspective, but the issue stems from the monolithic nature of the Seahub backend, where API endpoints are not exempt from the global web security middleware. The upgrade to a newer Django version has made these checks more stringent, exposing this conflict between session-based and token-based clients.
I will give the issue more check, once I have time.
It’s an operating system problem probably not Seafile’s configuration. The generation of thumbnails is done by the operating system if you use Windows I know that sometimes it is not very stable everything also depends on how the client is encoded.