Skip to main content
De MercureBroadcaster die op deze pagina wordt behandeld, is toegevoegd in laravel/framework PR #61474 (gemerged op 10 september 2026). Op het moment van schrijven maakt hij nog geen deel uit van een getagde release en staat hij ook niet in de officiële documentatie. Deze pagina is een preview op basis van de broncode en docblocks — controleer de changelog van laravel/framework voordat je hier in productie op vertrouwt.

Overzicht

De broadcastinglaag van Laravel biedt al lange tijd de “WebSocket-native” drivers Reverb, Pusher en Ably. Aan config/broadcasting.php is nu een nieuwe driverwaarde mercure toegevoegd. Mercure is een realtime protocol dat op Server-Sent Events (SSE) is gebouwd in plaats van op een bidirectionele WebSocket-verbinding. Het gedraagt zich meer als long-polling over HTTP/1.1 of HTTP/2, wat een aantal onderscheidende eigenschappen oplevert:
  • Het gaat transparant door gewone HTTP-infrastructuur heen (reverse proxies, CDN’s, load balancers).
  • Clients kunnen worden geïmplementeerd met alleen de EventSource-API van de browser — er is geen aparte clientbibliotheek nodig.
  • FrankenPHP heeft een ingebouwde Mercure-hub, dus je hebt geen extra infrastructuur nodig om ermee te experimenteren.

De nieuwe driver-waarde

In de commentaarregel bovenaan config/broadcasting.php met ondersteunde drivers staat nu ook mercure:
Er is ook een voorbeeldconfiguratie voor de connectie beschikbaar:
Als je url weglaat, valt de driver terug op de ingebouwde Mercure-hub van FrankenPHP (de functie mercure_publish()). Die beslissing wordt genomen in CreatesMercureDrivers::mercure():
Als je een externe hub draait, moet url verwijzen naar de management-API die voor publishen wordt gebruikt, terwijl public_url de URL is waarmee de browser verbinding maakt. Door beide te splitsen worden opstellingen ondersteund waarbij publishen via een intern netwerk gebeurt (bijvoorbeeld Docker Compose) en alleen de publieke URL naar de browser wordt blootgesteld.

Gescheiden publish- en subscribe-tokens

Mercure is een op JWT gebaseerd protocol voor toegangscontrole. De trait CreatesMercureDrivers bouwt aparte token-factories voor publishen (server → hub) en subscriben (browser → hub):
  • secret, publish_secret en subscribe_secret kunnen onafhankelijk van elkaar worden geconfigureerd; bij afwezigheid vallen ze terug op secret.
  • algorithm, publish_algorithm en subscribe_algorithm kunnen op dezelfde manier per kant worden ingesteld (standaard HS256).
  • HS256 vereist een secret van minimaal 32 bytes, HS384 minimaal 48 en HS512 minimaal 64; anders wordt een InvalidArgumentException gegooid.
Het publish-token draagt Grant::ACTION_PUBLISH voor alle topics (*) en wordt gememoïseerd door CachingTokenProvider, zodat er niet bij elke afzonderlijke broadcast-aanroep een nieuwe JWT hoeft te worden gegenereerd. Het grootste architecturale verschil met de WebSocket-drivers is dat de autorisatie van abonnees via één cookie verloopt. MercureBroadcaster::auth() accepteert een array channel_names (met een limiet van 100 per request), beoordeelt de autorisatie per kanaal en geeft vervolgens één enkele autorisatiecookie uit die alle kanalen omvat:
Cruciaal is dat één geweigerd kanaal niet de hele respons laat mislukken — het wordt in de responsepayload gemarkeerd als denied: true, terwijl de overige geautoriseerde kanalen gewoon blijven werken. Dat is belangrijk omdat Mercure meerdere topics multiplext over één EventSource-verbinding, zodat kanalen halverwege een sessie kunnen worden toegevoegd of verwijderd zonder de verbinding te verbreken. Presence-kanalen krijgen een andere Grant-vorm dan gewone private- of private-encrypted-kanalen, gericht op het subscribe-URL-patroon dat door Mercure’s Subscription-API wordt gebruikt.

End-to-end versleutelde kanalen

Kanalen met het prefix private-encrypted- worden behandeld als end-to-end versleuteld (E2EE) — dat betekent dat zelfs de Mercure-hub zelf de payload nooit te zien krijgt. Dit is een mogelijkheid die de bestaande Pusher- en Reverb-drivers niet bieden. Als je een base64-gecodeerde encryption_key van 32 bytes instelt, wordt de ChannelEncrypter geactiveerd. Die verpakt de eventnaam, de payload en het socket-ID in een JWE (JSON Web Encryption) voordat broadcast() het verstuurt. De hub geeft alleen versleutelde bytes door.
Abonnees ontsleutelen in de browser met behulp van het jwk-veld (JSON Web Key) dat door de auth()-respons wordt teruggegeven — een out-of-band-sleuteluitwisseling die door de Mercure-specificatie wordt aanbevolen, waardoor de hub de sleutel nooit leert kennen.
Presence-kanalen kunnen niet worden versleuteld, omdat hun ledenlijst per ontwerp via de Subscription-API van de hub loopt — dat is onverenigbaar met E2EE.

Whispers (directe berichten tussen clients)

Wanneer client_events is ingeschakeld (de standaard), krijgt elk beschermd kanaal een speciaal “whisper-topic” toegewezen waar abonnees op mogen publishen:
Het eigenlijke topic van het kanaal blijft alleen voor de server, zodat een client nooit een event kan vervalsen dat afkomstig lijkt van de server. Dit lijkt op de “client events”-functie van Pusher, maar houdt de autorisatie duidelijk gescheiden door aparte topics te gebruiken.

Naamgeving van topics

Omdat Mercure-hubs vaak door meerdere applicaties worden gedeeld, worden topics genamespaced onder een topic_prefix om botsingen te voorkomen. De standaardwaarde is:
.alt is een gereserveerd, niet-resolvbaar DNS-suffix (RFC 9476), dus het kan nooit botsen met een echt domein. Kanaalnamen worden URL-encoded volgens RFC 3986 en in één padsegment gestopt:

Cookiedomein en foutmeldingen

Omdat een Mercure-hub vaak op een ander subdomein draait dan de applicatie (bijvoorbeeld mercure.example.com versus app.example.com), wordt er een beschrijvende exception gegooid als er geen gedeeld cookiedomein kan worden bepaald:
Als je een cookienaam gebruikt met het prefix __Secure- of __Host-, controleert de driver bij het opstarten ook of public_url HTTPS is:

Kiezen tussen Reverb, Pusher/Ably en Mercure

Mercure is een goede keuze wanneer je geen persistente bidirectionele verbinding nodig hebt — denk aan notificaties, voortgangsupdates of chat-achtige use cases die vooral van server naar client gaan. Als je al FrankenPHP draait, werkt het zelfs zonder enige extra infrastructuur.

Gerelateerde pagina’s

Laatst gewijzigd op 13 september 2026