Kozea / Kozea/Radicale

WebUI authentication broken through Cloudflare proxy with strict browsers (e.g. Librewolf)

Open
#2,096 6 comments 0 reactions 1 assignee Claimed by @maxberger View on GitHub
need:reporter feedback reverse proxy webui
Dominant language
Python
Stars
5k
Forks
524
Avg merge
15h 15m
Merged PRs (30d)
17

Description

Hi,

I recently migrated from `tomsquest/docker-radicale` to the official `ghcr.io/kozea/radicale:stable` image and ran into an issue with the WebUI getting stuck on the loading spinner when accessed through a reverse proxy (Nginx Proxy Manager) with Cloudflare proxy enabled.

After a lot of debugging, I found that the new WebUI introduced in 3.7.0 handles authentication via XHR requests in JavaScript, whereas the older WebUI triggered a native browser Basic Auth popup. This change in behavior causes two related issues.

First, when Cloudflare proxy is active, it modifies response headers in transit, stripping or altering the CORS and `WWW-Authenticate` headers that the WebUI JavaScript needs to handle the 401 response and display the login form. This results in the WebUI being stuck on the spinner indefinitely. Adding `Access-Control-Allow-Origin` and related headers in the `[headers]` section of the Radicale config partially helps, but Cloudflare still interferes.

Second, privacy-hardened browsers like Librewolf are stricter about XHR-based Basic Auth challenges than standard Firefox or Chromium. With the old WebUI (native browser popup), Librewolf worked fine. With the new JS-based auth, Librewolf gets stuck on the spinner even when Cloudflare is bypassed — unless specific CORS headers are explicitly set in Radicale's config.

Disabling the Cloudflare proxy (DNS only mode) and adding the CORS headers to the Radicale config fixes everything for standard browsers. Librewolf works too once Cloudflare is out of the picture.

This might be worth documenting in the reverse proxy section, specifically that the new WebUI requires proper CORS headers and that Cloudflare proxy mode can break the authentication flow. A note about privacy-hardened browsers would also be helpful.

For reference, here is the `[headers]` config that made things work:

```ini
[headers]
Access-Control-Allow-Origin = https://your-domain.com
Access-Control-Allow-Methods = GET, POST, PUT, DELETE, PROPFIND, PROPPATCH, MKCALENDAR, MKCOL, REPORT, OPTIONS
Access-Control-Allow-Headers = Authorization, Content-Type, Depth, If-Match, If-None-Match
Access-Control-Expose-Headers = DAV, content-type, WWW-Authenticate
```

Thanks for the great work, the sharing feature is exactly what I needed.

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.