Hey.
Our setup is Laravel Reverb, headless Vue 3 and for auth we use Amazon Cognito.
The app is private and all Broadcast channels are private.
When the page loads, the bearer token is not yet available as I'm just sending the Cognito auth code to my backend and only then I get the bearer token.
The problem is that Echo already loads and fails the auth which I don't see how to retry.
What I'm doing now is that when the bearerToken is available, I reconnect the channel.
The problem is that it loses all connections and listeners to the events.
What's the correct way to use it? The documentation for Echo doesn't exist, so I was going through the code itself.
useEcho.ts
import Echo from "laravel-echo";
import Pusher from "pusher-js";
(window as any).Pusher = Pusher;
const useEcho = new Echo({
broadcaster: "reverb",
key: import.meta.env.VITE_REVERB_APP_KEY,
cluster: import.meta.env.VITE_REVERB_CLUSTER, // Pusher isn't working without noticing cluster
wsHost: import.meta.env.VITE_REVERB_HOST,
wsPort: import.meta.env.VITE_REVERB_PORT ?? 80,
wssPort: import.meta.env.VITE_REVERB_PORT ?? 443,
forceTLS: (import.meta.env.VITE_REVERB_SCHEME ?? "https") === "https",
enabledTransports: ["ws", "wss"],
authEndpoint: import.meta.env.VITE_REVERB_BROADCAST_AUTH_ENDPOINT,
bearerToken: localStorage.getItem("accessToken"),
});
// On connection, console.log "Connected to Reverb"
useEcho.connector.pusher.connection.bind("connected", () => {
// eslint-disable-next-line no-console
console.log("Connected to WS");
});
export const reconnectEcho = (bearerToken: string) => {
const subscribedChannels = useEcho.connector.pusher.channels.all();
useEcho.disconnect();
useEcho.options.bearerToken = bearerToken;
useEcho.connect();
subscribedChannels.forEach((channel) => {
useEcho.channel(channel.name);
});
};
export default useEcho;
auth.ts
checkIfTokenIsStored() {
const token = localStorage.getItem("accessToken");
if (token) {
useHttp.defaults.headers.common.Authorization = `Bearer ${token}`;
this.isAuthenticated = true;
if (!this.isEchoAuthenticated) {
reconnectEcho(token);
this.isEchoAuthenticated = true;
}
}
},
Notifications.vue
useEcho
.private(`user-notifications.${userStore.user.id}`)
.on("notification-downloaded", (event: { notification: Notification }) => {
toast.success(event.notification.title, {
description: event.notification.message,
});
notifications.value.unshift(event.notification);
})
.on("notification-error", (event: { notification: Notification }) => {
toast.error(event.notification.title, {
description: event.notification.message,
});
notifications.value.unshift(event.notification);
});