symfony / mercure

The Mercure Component allows to easily push updates to web browsers and other HTTP clients using the Mercure protocol.
https://symfony.com/doc/current/components/mercure.html
MIT License
413 stars 39 forks source link

Subscription from client give error #76

Closed Wimble84 closed 2 years ago

Wimble84 commented 2 years ago

What does the error "The default hub does not contain a token factory" means ?

I face it when trying to subscribe on private update from my client.

I'm on Ubuntu 20.04 and it's based on Docker env (Apache2, PHP8, Mercure 0.13.0, Symfony 5.3). Here is the mercure docker-compose container

mercure:
        image: dunglas/mercure
        container_name: mercure
        restart: unless-stopped
        ports:
            - "81:80"
        environment:
            MERCURE_PUBLISHER_JWT_KEY: '!ChangeMe!'
            MERCURE_SUBSCRIBER_JWT_KEY: '!ChangeMe!'
            CORS_ALLOWED_ORIGINS: '*'
            MERCURE_CORS_ALLOWED_ORIGINS: '*'
            PUBLISH_ALLOWED_ORIGINS: '*'
            ALLOW_ANONYMOUS: '1'
            MERCURE_EXTRA_DIRECTIVES: cors_origins *
            SERVER_NAME: ":80"
        command: /usr/bin/caddy run -config /etc/caddy/Caddyfile.dev
        volumes:
            - mercure_data:/data
            - mercure_config:/config
        networks:
            - server

I succesfully send update to my twig page. But when I try to use Authorization on subscription by this way

/**
     * @Route("/ping/{user}", name="ping", methods={"POST"})
     */
    public function ping(HubInterface $hub, ?User $user = null): Response
    {

            $update = new Update(
                'user/' . $user->getId(),
                json_encode(['message' => 'PING FROM ' . $this->getUser()->getUserIdentifier() . ' TO ' . $user->getUserIdentifier() .  ' !']),
                true
            );

        $hub->publish($update);

        return $this->redirectToRoute('index');
    }
const eventSource = new EventSource("{{ mercure('user/' ~ app.user.id, { subscribe: 'user/' ~ app.user.id })|escape('js') }}", {
    withCredentials: true
});

eventSource.onmessage = e => {
    console.log('HELLO');
};

Mercure configuration

mercure:
    hubs:
        default:
            url: '%env(MERCURE_URL)%'
            public_url: '%env(MERCURE_PUBLIC_URL)%'
            jwt:
                secret: '%env(MERCURE_JWT_SECRET)%'
                publish: '*'
                provider: App\Service\MercureJwtProvider

.env related vars

MERCURE_URL=http://mercure/.well-known/mercure
MERCURE_PUBLIC_URL=http://localhost:81/.well-known/mercure
MERCURE_JWT_SECRET=!ChangeMe!

MercureJwtProvider used in configuration

<?php

namespace App\Service;

use Lcobucci\JWT\Configuration;
use Lcobucci\JWT\Signer\Hmac\Sha256;
use Lcobucci\JWT\Signer\Key\InMemory;
use Symfony\Component\Mercure\Jwt\TokenProviderInterface;

class MercureJwtProvider implements TokenProviderInterface
{
    private string $secret;

    public function __construct(string $secret)
    {
        $this->secret = $secret;
    }

    public function getJwt(): string
    {
        $configuration = Configuration::forSymmetricSigner(
            new Sha256(),
            InMemory::plainText($this->secret)
        );

        return $configuration
            ->builder()
            ->withClaim('mercure', ['publish' => ['*'], 'subscribe' => ['*']])
            ->getToken(
                $configuration->signer(),
                $configuration->signingKey()
            )
            ->toString();
    }
}

From the moment i use withCrededntial: true I get the error ...

I can open a repo of current code if needed.

gurgenhakobyan commented 2 years ago

@Wimble84 I'm facing the same issue, did you find a solution?