Skip to content

Stop the Mercure hub from accepting anonymous subscribers - #287

Closed
fashxp wants to merge 1 commit into
2026.2from
fix/pv346-mercure-hub-hardening-2026.2
Closed

Stop the Mercure hub from accepting anonymous subscribers#287
fashxp wants to merge 1 commit into
2026.2from
fix/pv346-mercure-hub-hardening-2026.2

Conversation

@fashxp

@fashxp fashxp commented Aug 20, 2026

Copy link
Copy Markdown
Member

Part of the fix for pimcore/platform-version#346.

Problem

MERCURE_EXTRA_DIRECTIVES: anonymous lets the hub accept a subscription that carries no valid
mercureAuthorization cookie. Such a subscription is answered 200 OK and then silently
receives nothing
, because every update Studio publishes is a private update.

That turns an authorisation problem into invisible data loss. A Studio tab whose cookie expired
(it lives one hour; the tab lives as long as the user leaves it open) keeps what looks like a
perfectly healthy stream while notifications, job progress and agent chat events are all dropped,
with no error anywhere, until the page is fully reloaded. Measured on a real installation, a tab
ran in that state for five hours across ~31 reconnects.

Change

Drop the anonymous directive. An unauthorised subscription now gets 401, which the client can
see and react to. Nothing in Pimcore subscribes to the hub anonymously: Studio always holds a
cookie, and pimcore/studio-ui-bundle#4009 makes every reconnect renew it and retry.

Verification

Started dunglas/mercure with MERCURE_EXTRA_DIRECTIVES: '' and probed it:

Subscriber Before (anonymous) After
no cookie 200 OK, private update not delivered 401
valid subscriber JWT 200 OK, delivered 200 OK, delivered
expired subscriber JWT 401 401

The hub starts cleanly with an empty directive list, and authorised delivery is unchanged.

Not included

The demo ships .docker/nginx.conf; the skeleton ships one too, and in both the location /hub block has no SSE specific proxy settings (proxy_buffering off,
proxy_read_timeout, proxy_http_version 1.1). That is worth a separate look, but it is a
different concern from this bug and is deliberately left out of this PR: measurements showed the
hub's ~40s heartbeat keeps the stream inside nginx's default 60s idle timeout, so it is hardening
rather than a fix.

An unauthorised subscription was answered 200 OK and then received nothing, so a
Studio tab whose cookie had expired kept a healthy looking stream with no live
updates at all. Answering 401 makes that state visible and recoverable.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@fashxp

fashxp commented Aug 21, 2026

Copy link
Copy Markdown
Member Author

Closing for consistency with pimcore/demo-enterprise#528.

The skeleton itself ships neither Direct Edit nor Portal Engine, so the change is safe as it stands - but both bundles are commonly added to a skeleton install, and Portal Engine's Direct Edit status indicator subscribes to the hub without a token (DirectEditStatus.js: new EventSource(url), no credentials, on a public topic). Making the skeleton's hub reject anonymous subscribers would break that as soon as those bundles are installed, and the failure is silent - onerror is an empty function.

Keeping anonymous until the bundles that subscribe without a token authorize their subscriptions. Tracked separately.

The actual fix for pimcore/platform-version#346 is pimcore/studio-ui-bundle#4009, which re-authorizes on every reconnect; this hardening was defence in depth on top of it.

@fashxp fashxp closed this Aug 21, 2026
@fashxp
fashxp deleted the fix/pv346-mercure-hub-hardening-2026.2 branch August 21, 2026 07:40
@github-actions github-actions Bot locked and limited conversation to collaborators Aug 21, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Studio UI] Mercure subscription silently falls back to anonymous 1 hour after page load, all live updates stop

1 participant