PubSub broadcast, listen not called

Hi, I got as far as I could searching the forum but now I’m stuck.

I’m trying to send a message from nodejs EBS to my extension. The extension is running inside twitch channel panel.

Issues overcome:

  • invalid payload = 400 Bad Request
  • use extension client id rather than application client id = 403
  • base64 decode extension secret before signing = 404

Now I have 204, but “listen” in extension not called, “onAuthorized” is.

For the channelID I am using “all”. How can I find the ID of my own channel?


// Create and return a JWT for use by this service.
function makeServerToken(channelId) {
    const payload = {
        exp: Math.floor( / 1000) + serverTokenDurationSec,
        channel_id: channelId,
        role: 'external',
        pubsub_perms: {
            send: ['*'],
    return jsonwebtoken.sign(payload, extensionSecret, { algorithm: 'HS256' });


// because who wants to type this every time?
var twitch = window.Twitch.ext;

let isAuthed = false;
twitch.listen('broadcast', (target, contentType, message) => {
        if (isAuthed) {
            console.log(target, contentType, message);
        } else {
            //ignore as not authed

twitch.onAuthorized(function () {
    isAuthed = true;

I am testing locally, without the rig, but via ngrok.

I’ll update with my own answer.

I found (RTFM) that the channelId can be obtained from the Object passed to onAuthorized

twitch.onAuthorized(function (auth) {
    isAuthed = true;
    console.log('The JWT that will be passed to the EBS is', auth.token);
    console.log('The channel ID is', auth.channelId);

I then passed this channelId to my makeServerToken function. Ensuring that it’s forced to a string.

When making a server token.

I’m assuming this is on an EBS.

You can obtain the channelID the extension was called from, by passing up the JWT token from your frontend to the backend.

As the JWT will contain the channel_id, and since you verified the JWT you know for sure the channelID that the extension was loaded up on.

Example EBS:

This Example EBS intends to lookup the user that is logged into the extension, but the channelID is also in the verified JWT.

So for a “server”, if the extension is allowlisted to one channel, you can hardcode the channeID, having used the users API to convert a login to an ID.
But if it’s intended to work on multiple channels, you can extract the channelID from JWT or depending on the data you are relaying to the frontend from the backend use the “all”/global topic.

So if your frontend extension passes up the JWT you only have to pass up the JWT, not multiple bits of data, and the JWT can be verified and the channelID known for sure.

The ChannelID obtained from onAuthorized, should only be used in the frontend and not passed to the backend, since people could modify the data. So you should extract the channelID from the JWT from a security persepctive.

See also the JWT Schema docs