What I want to solve
I want to implement Laravel-Echo to my Nuxt3 Application. As Laravel is my backend, I am using Sanctum as auth provider.
What my attempt looks like
I am using nuxt-auth-sanctum, which works nice for my purpose (so far). This is the nuxt.conf.ts
:
// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
modules: [
'@nuxt/content',
'@vueuse/nuxt',
'nuxt-auth-sanctum'
],
runtimeConfig: {
backendUrl: process.env.NUXT_BACKEND_URL,
public: {
pusherKey: process.env.NUXT_PUBLIC_PUSHER_KEY,
pusherHost: process.env.NUXT_PUBLIC_PUSHER_HOST,
pusherWsPort: process.env.NUXT_PUBLIC_PUSHER_WS_PORT,
pusherWssPort: process.env.NUXT_PUBLIC_PUSHER_WSS_PORT,
pusherScheme: process.env.NUXT_PUBLIC_PUSHER_SCHEME,
pusherCluster: process.env.NUXT_PUBLIC_PUSHER_CLUSTER
}
},
sanctum: {
baseUrl: `${process.env.NUXT_PUBLIC_SITE_URL}/backend/api/${process.env.NUXT_API_VERSION}`,
origin: process.env.NUXT_PUBLIC_SITE_URL,
endpoints: {
csrf: `${process.env.NUXT_PUBLIC_SITE_URL}/backend/csrf`,
login: `${process.env.NUXT_PUBLIC_SITE_URL}/backend/auth/login`,
logout: `${process.env.NUXT_PUBLIC_SITE_URL}/backend/auth/logout`,
user: '/auth/me'
},
logLevel: 4,
redirect: {
keepRequestedRoute: true,
onLogin: '/dashboard',
onLogout: '/',
onAuthOnly: '/login',
onGuestOnly: '/dashboard'
}
},
routeRules: {
'/backend/api/v1/**': {
proxy: {
to: `${process.env.NUXT_BACKEND_URL}/api/${process.env.NUXT_API_VERSION}/**`,
headers: { accept: 'application/json' }
}
},
'/backend/web/**': {
proxy: {
to: `${process.env.NUXT_BACKEND_URL}/**`,
headers: { accept: 'application/json' }
}
},
'/backend/auth/**': {
proxy: {
to: `${process.env.NUXT_BACKEND_URL}/auth/**`,
headers: { accept: 'application/json' }
}
},
'/backend/csrf': {
proxy: `${process.env.NUXT_BACKEND_URL}/sanctum/csrf-cookie`,
headers: { accept: 'application/json' }
},
'/broadcasting/auth': {
proxy: `${process.env.NUXT_BACKEND_URL}/api/${process.env.NUXT_API_VERSION}/broadcasting/auth`,
headers: { accept: 'application/json' }
},
'/api/search.json': { prerender: true },
'/docs': { redirect: '/docs/getting-started', prerender: false }
},
devtools: {
enabled: true
},
})
This is the echo plugin file called echo.client.ts
:
import Echo from 'laravel-echo'
import Pusher from 'pusher-js'
import {
useCookie
} from '#app'
declare global {
interface Window {
pusher: any
}
}
export default defineNuxtPlugin(() => {
window.pusher = Pusher
const config = useRuntimeConfig().public
const token = useCookie('XSRF-TOKEN')
const echo = new Echo({
broadcaster: 'pusher',
key: config.pusherKey,
wsHost: config.pusherHost,
wsPort: config.pusherWsPort,
wssPort: config.pusherWssPort,
forceTLS: (config.pusherScheme ?? 'https') === 'https',
enabledTransports: ['ws', 'wss'],
cluster: config.pusherCluster,
auth: {
headers: {
'X-XSRF-TOKEN': token.value
}
}
})
return {
provide: {
echo: echo
}
}
})
It is actually possible to login and subscribe to a channel like this:
onMounted(() => {
$echo.private(`Order.${props.order.uuid}`).listen('.OrderShipped', () => {
refresh()
})
})
This makes this call:
fetch("http://web.example.test/broadcasting/auth", {
"headers": {
"accept": "*/*",
"accept-language": "de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7",
"content-type": "application/x-www-form-urlencoded",
"x-xsrf-token": "...="
},
"referrer": "http://web.example.test/orders",
"referrerPolicy": "strict-origin-when-cross-origin",
"body": "socket_id=6189903872.1771283099&channel_name=private-Order.9c571400-9c2e-4d8a-bdbb-088ea138b0d5",
"method": "POST",
"mode": "cors",
"credentials": "include"
});
What is my problem
Now the strange thing happens here:
If I subscribe to another channel like this:
onMounted(() => {
currentProject.value = data.value.data[selectedProject.value]
$echo.private(`User.${user.value.uuid}`).listen('.OrderCreated', () => {
refresh()
})
})
the subscription process works out fine, too. But if I refresh the page, I am getting logged out. If I remove one $echo.private()
-statement, this does not happen. If I just use $echo.channel()
(not private), this is not happening, too.
On the Laravel database’s sessions
table I can see that in these cases a new session is being created after refresh without an assigned user_id
.
Sessions before using $echo.private()
id | user_id | ip_address | user_agent | payload | last_activity |
---|---|---|---|---|---|
3WmQR4XDqsqxDXOFwJvldLbHklf7xcIAvRxmf8Ba | 9c5cb8de-3a80-41ea-b5c7-21c6a921e548 | 127.0.0.1 | Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 | YTo1OntzOjY6Il90b2tlbiI7czo0MDoidHhjekU4RzNhSW8wb0xUVUdTS1hlYTRCWjdEcWtGckMzNDlOYjNVRyI7czo5OiJfcHJldmlvdXMiO2E6MTp7czozOiJ1cmwiO3M6ODA6Imh0dHA6Ly9hcGkuaG9zdHIudGVzdC9hcGkvdjEvcHJvamVjdC8wMTkwNDk4Ny01N2E2LTczM2YtYTVhMy0wNzA1MzFmZDkyMjQvc2VydmVyIjt9czo2OiJfZmxhc2giO2E6Mjp7czozOiJvbGQiO2E6MDp7fXM6MzoibmV3IjthOjA6e319czo1MDoibG9naW5fd2ViXzU5YmEzNmFkZGMyYjJmOTQwMTU4MGYwMTRjN2Y1OGVhNGUzMDk4OWQiO3M6MzY6IjljNWNiOGRlLTNhODAtNDFlYS1iNWM3LTIxYzZhOTIxZTU0OCI7czoxNzoicGFzc3dvcmRfaGFzaF93ZWIiO3M6NjA6IiQyeSQxMiRPZjZWQzkvc2IxcDFoT1VVUmJtNWJPcEZDckhwMzF0Z1JNcDI2aDZFTWlQVXVBVEhFTHZiLiI7fQ== | 1719306465 |
Sessions after refresh
id | user_id | ip_address | user_agent | payload | last_activity |
---|---|---|---|---|---|
3WmQR4XDqsqxDXOFwJvldLbHklf7xcIAvRxmf8Ba | 9c5cb8de-3a80-41ea-b5c7-21c6a921e548 | 127.0.0.1 | node | YTo1OntzOjY6Il90b2tlbiI7czo0MDoidHhjekU4RzNhSW8wb0xUVUdTS1hlYTRCWjdEcWtGckMzNDlOYjNVRyI7czo5OiJfcHJldmlvdXMiO2E6MTp7czozOiJ1cmwiO3M6MzY6Imh0dHA6Ly9hcGkuaG9zdHIudGVzdC9hcGkvdjEvYXV0aC9tZSI7fXM6NjoiX2ZsYXNoIjthOjI6e3M6Mzoib2xkIjthOjA6e31zOjM6Im5ldyI7YTowOnt9fXM6NTA6ImxvZ2luX3dlYl81OWJhMzZhZGRjMmIyZjk0MDE1ODBmMDE0YzdmNThlYTRlMzA5ODlkIjtzOjM2OiI5YzVjYjhkZS0zYTgwLTQxZWEtYjVjNy0yMWM2YTkyMWU1NDgiO3M6MTc6InBhc3N3b3JkX2hhc2hfd2ViIjtzOjYwOiIkMnkkMTIkT2Y2VkM5L3NiMXAxaE9VVVJibTViT3BGQ3JIcDMxdGdSTXAyNmg2RU1pUFV1QVRIRUx2Yi4iO30= | 1719306524 |
WkmfEZCgy1I8apuHvU77fT8I9GWO64Yl7eLnRVwo | 127.0.0.1 | node | YTozOntzOjY6Il90b2tlbiI7czo0MDoibWw1dXhSUGYzOUVUdWx4WUtiQlZFbFg3cTB0c1lKbWJRRTV4MVZDciI7czo5OiJfcHJldmlvdXMiO2E6MTp7czozOiJ1cmwiO3M6MzY6Imh0dHA6Ly9hcGkuaG9zdHIudGVzdC9hcGkvdjEvYXV0aC9tZSI7fXM6NjoiX2ZsYXNoIjthOjI6e3M6Mzoib2xkIjthOjA6e31zOjM6Im5ldyI7YTowOnt9fX0= | 1719306526 |