# Real-time FrankenPHP comes with a built-in [Mercure](https://mercure.rocks) hub! Mercure allows you to push real-time events to all the connected devices: they will receive a JavaScript event instantly. It's a convenient alternative to WebSockets that is simple to use and is natively supported by all modern web browsers! ![Mercure](mercure-hub.png) ## Enabling Mercure Mercure support is disabled by default. Here is a minimal example of a `Caddyfile` enabling both FrankenPHP and the Mercure hub: ```caddyfile # The hostname to respond to localhost mercure { # The secret key used to sign the JWT tokens for publishers publisher_jwt !ChangeThisMercureHubJWTSecretKey! # Allows anonymous subscribers (without JWT) anonymous } root public/ php_server ``` > [!TIP] > > The [sample `Caddyfile`](https://github.com/php/frankenphp/blob/main/caddy/frankenphp/Caddyfile) > provided by [the Docker images](docker.md) already includes a commented Mercure configuration > with convenient environment variables to configure it. > > Uncomment the Mercure section in `/etc/frankenphp/Caddyfile` to enable it. ## Subscribing to Updates By default, the Mercure hub is available on the `/.well-known/mercure` path of your FrankenPHP server. To subscribe to updates, use the native [`EventSource`](https://developer.mozilla.org/docs/Web/API/EventSource) JavaScript class: ```html Mercure Example ``` ## Publishing Updates ### Using `file_put_contents()` To dispatch an update to connected subscribers, send an authenticated POST request to the Mercure hub with the `topic` and `data` parameters: ```php [ 'method' => 'POST', 'header' => "Content-type: application/x-www-form-urlencoded\r\nAuthorization: Bearer " . JWT, 'content' => http_build_query([ 'topic' => 'my-topic', 'data' => json_encode(['key' => 'value']), ]), ]])); // Write to FrankenPHP's logs error_log("update $updateID published", 4); ``` The key passed as parameter of the `mercure.publisher_jwt` option in the `Caddyfile` must used to sign the JWT token used in the `Authorization` header. The JWT must include a `mercure` claim with a `publish` permission for the topics you want to publish to. See [the Mercure documentation](https://mercure.rocks/spec#publishers) about authorization. To generate your own tokens, you can use [this jwt.io link](https://www.jwt.io/#token=eyJhbGciOiJIUzI1NiJ9.eyJtZXJjdXJlIjp7InB1Ymxpc2giOlsiKiJdfX0.PXwpfIGng6KObfZlcOXvcnWCJOWTFLtswGI5DZuWSK4), but for production apps, it's recommended to use short-lived tokens generated aerodynamically using with a trusted [JWT library](https://www.jwt.io/libraries?programming_language=php). ### Using Symfony Mercure Alternatively, you can use the [Symfony Mercure Component](https://symfony.com/components/Mercure), a standalone PHP library. This library handled the JWT generation, update publishing as well as cookie-based authorization for subscribers. First, install the library using Composer: ```console composer require symfony/mercure lcobucci/jwt ``` Then, you can use it like this: ```php publish(new \Symfony\Component\Mercure\Update('my-topic', json_encode(['key' => 'value']))); // Write to FrankenPHP's logs error_log("update $updateID published", 4); ``` Mercure is also natively supported by: - [Laravel](laravel.md#mercure-support) - [Symfony](https://symfony.com/doc/current/mercure.html) - [API Platform](https://api-platform.com/docs/core/mercure/)