Block content in config extension

I am trying to create a simple extension, basically a panel, with a button, when pressed a message is spammed to the chat ( let’s say the broadcaster will be the user)

I understand that to send a message Sending and Receiving Chat Messages | Twitch Developers you have to use a “Implicit grant flow”, this is like a form.

So, to get the token from here if I want to use it in a extension, I made it so that the config.html is where the streamer gets access to the token, so basically in the config.html I add :

<a href="https://id.twitch.tv/oauth2/authorize?[parameters]">Connect with Twitch</a>

parameters being the ones I give it, this works in my localhost testing it out, I get the form, and then the token, but if I want to use this is in the config.html to save the token I get :

Maybe there is another approach?
Thank you

A few things, first you shouldn’t be sending users to different sites/pages within the Extension iframe. You would need a new window for this. Extension Iframes should be treated as a Single Page App.

Secondly, the implicit flow tokens expire with no way to refresh them so you would need the broadcaster to go through this process each and every time, which while it will work it’s a poor choice.

Thirdly, permissions to send messages as the broadcaster is a very risky scope to be requesting and not many broadcasters would be willing to grant it so you may wish to consider other options such as a bot. Also because it would use the broadcasters token it means no other user on the channel could interact with the Extension as you’d be exposing the broadcasters token to other users.

For an extension you want

Send Extension Chat Message: Reference | Twitch Developers

As then you send messages as the Extension not as the broadcaster. And as noted by dist

They already installed the extension.

So you can use extension chat no additional authentication needed

Or your own bot. My preference is usually send extension chat message but depends on what the use case and the messages being sent

Pada tanggal Rab, 19 Feb 2025 18.35, Barry Carlyon via Twitch Developer Forums <no-reply@twitch.com> menulis:

(attachments)

Not sure what this relates to

Thanks for the reply, I just wanted to see what would be the best approach to create a panel with a button, once press it sends a pre defined message to the chat.

So for these kinds of things I should not use the implicit flow token?

You mention a bot, I want to start creating extensions , is there a way to integrate a bot with extensions?

Thanks

It seems that I need to sign a JWT Building Extensions | Twitch Developers

do I need to have a backend listening to localhost:3000 to manage this?, I see this code

const jwt = require('jsonwebtoken')

const sharedSecret = 's7sK6iKws1KS+ihSERL7fgoT8rx90iFkJ/hUdcAEGSs='
const broadcasterId = '12345678'
const tokenPayload = {
    user_id: broadcasterId,
    role: 'external'
}

const token = jwt.sign(tokenPayload, Buffer.from(sharedSecret, 'base64'), { expiresIn: '1d' })
console.log("token: " + token)

replacing my sharedSecret and broadcasterId

I hope I dont need a backend to do this, can’t it be done loading this javascript in the panel.html to get the token?

You’ll need a backend somewhere web accessable for this yes.

Just like you would if you were doing a chatbot or sending chat messages. (assuming not sending as a streamer for the reasons discussed)

No that would leak your extension secret and be abusable in a variety of ways.

With a backend yes.

Given you don’t know the redirect URI as it changes on upload of extension assets, you basically can’t without a backend.

A backend would be optimal, for an extension that does “rich” responses.

So the question follows: what does you extension do, whare are you building, what sort of messaging will it be sending?

Edit: it is worth noting that a broadcaster JWT is valid to send to the broadcasters own channel. So if the config view is open and stays open then chat messages can be sent using that JWT, but, you shouldn’t expect a streamer to keep the config view open to operate the extension. But this will depend what you extension does

Im just doing case scenaries to see what I can offer my clients has a twitch extension developer, it seems that I won’t be able to do this, do you know how other developers do the backend, do they use a hosting provider of somesort?

I remember you showed me 2 extensions you made regarding making extensions unique to a streamer, Creator Dashboard and Creator Dashboard

With out using the backend, then there is a limite amount of tools that i can created has a extension

Thanks

Both of these have backends.

Backends can be in whatever languge you want on whatever hosting you want.

You the extension developer as responsible for hosting the backend, you jsut need to make sure that it has SSL (if it accepts HTTP requests). And is otherwise suitably secured just like “a regular website”

Arguable a backend offers more things an extension can do than requireing “complexities” to make it work without.

Most extensions that don’t have a backend are just consuming data from another API, so that other API is the backend there. It’s not common for an extension to not call anything external to it as that is very limiting.

You mean that the website has SSL ? so like a normal website like you say, okey I can work with this, thank you for all the advise, cleared a lot of things.

Currently I am just using nodejs to create a backend for testing, I assume client will have to provide the hosting service for me to later add the code, in my testing with nodejs is it posible to make it have a SSL certificate , I mean in testing environment (probably not a twitch question related)

I only have this code from tutorial, this doesnt have ssl correct?

/* Importing Libraries */
var express = require("express");
var bodyParser = require('body-parser');
const jwt = require('jsonwebtoken')



/* Express Step 1: Creating an express application */
var app = express();
//set port 
var port = 3000;

/* Express Step 2: Start Server */
app.listen(port, () => {
 console.log("Server listening on port " + port);
});

// Express Step 3: Use body-parser library to help parse incoming request bodies
app.use(bodyParser.json());
/* This is included because its allows extenion to run external javascript. 
If you are interested in learning more, check out: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS */
app.use((req, res, next) => {
  res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-Requested-With');
  res.setHeader('Access-Control-Allow-Methods', 'OPTIONS, GET, POST');
  // Note that the origin of an extension iframe will be null
  // so the Access-Control-Allow-Origin has to be wildcard.
  res.setHeader('Access-Control-Allow-Origin', '*');
  next();
});


app.get('/questions', (req, res) => {
    res.send("HOLA TU");
  });

For some reason I am still getting 401 unathorized :

{
    "error": "Unauthorized",
    "status": 401,
    "message": "authentication failed"
}

I am creating the sing JWT with the script :

/* Importing Libraries */
var express = require("express");
var bodyParser = require('body-parser');
const jwt = require('jsonwebtoken')

const sharedSecret = 'blablabla'
const broadcasterId = '1234'
const tokenPayload = {
    user_id: broadcasterId,
    role: 'external'
}

const token = jwt.sign(tokenPayload, Buffer.from(sharedSecret, 'base64'), { expiresIn: '1d' })
console.log(token)

In postman (where I test Apis) I add the Authorization with “Bearer previoustoken”

Also Body has :

{
  "text": "Helldo",
  "extension_id": "id_extension",
  "extension_version": "0.0.1"
}

Correct no SSL

Normal deployment of these normally places it behind nginx of similar which will handle SSL.

Is the

  • extension installed to the target channel
  • is the extension activated in a slot
  • is the permission enabled
  • if all three try full reinstall
  • if the JWT correctly built (1d is very long btw)
  • is your server time/the place where the JWT was made accurate
  • are you headers correctly defined
  • is the rest of the payload correct

Don’t know if you have ever used postman, I am using that to test api calls.

Reading this documentation Building Extensions | Twitch Developers and using this code I allready get the JWT signed, correct?

/* Importing Libraries */
var express = require("express");
var bodyParser = require('body-parser');
const jwt = require('jsonwebtoken')

const sharedSecret = 'blablabla'
const broadcasterId = '1234'
const tokenPayload = {
    user_id: broadcasterId,
    role: 'external'
}

const token = jwt.sign(tokenPayload, Buffer.from(sharedSecret, 'base64'), { expiresIn: '1d' })
console.log(token)

So what will give me a string always separated by a “.”, for example blablablabla.bleblebleble.bliblibliblibli

Then in postman I add to the header :

And in the body :

The extension is active and is set has a panel 1

Not sure if I am missing something

I don’t for extension stuff I use GitHub - BarryCarlyon/twitch_extension_tools: Tools for Twitch Developers to assist them working on a Twitch Extension saves faffing with JWT’s as the app JWT

The problem here is likely testing in post man so the advice is to move to code and test

The chat capability is also turned on?

Yes , it is turned on

I think I have used other extensions id by mistake, not sure, but now I am getting the following message on response :

{
    "error": "Unauthorized",
    "status": 401,
    "message": "The extension is not allowed to send a chat message to the specified broadcaster's chat room."
}

Finally got it working, my bad, had different extensions and had mix up with client-is, secrets,etc.
Lastly I remembered to have it installed has a panel and everything works, thanks for being pacient with me!

One more thing for undestanding the Token, I have to sign a token in the backend to send a ajax call to twitch so it knows it’s a “legitime” call, so what is the token for example, in the panel.html for?

// onAuthorized callback called each time JWT is fired
twitch.onAuthorized((auth) => {
  // save our credentials
  token = auth.token;  
  userId = auth.userId;
  console.log(auth)
});

Im my test code I dont need this token for anything because:

  1. Viewer sees panel
  2. Clicks on the button of the panel
  3. The panel has a viewer.js that handles the onclick of that button
  4. Button send ajax call to localhost:3000/button
  5. Backend is listening to port 3000/button
  6. Backend prepares to create the sign token with the shared secret to make a ajax call to the api that sends the chat message
const sharedSecret = 'secrt'
const broadcasterId = 'idd'
const tokenPayload = {
    user_id: broadcasterId,
    role: 'external'
}

const token = jwt.sign(tokenPayload, Buffer.from(sharedSecret, 'base64'), { expiresIn: '1d' })
var settings = {
    "url": "https://api.twitch.tv/helix/extensions/chat?broadcaster_id=otherid",
    "method": "POST",
    "timeout": 0,
    "headers": {
      "Authorization": "Bearer " + token,
      "Client-Id": "someid",
      "Content-Type": "application/json"
    },
    "data": JSON.stringify({
      "text": "Hello",
      "extension_id": "someid",
      "extension_version": "0.0.1"
    }),
  };

 $.ajax(settings).done(function (response) {
        res.send(response);
      });

and message in chat

Your backend could use this token to verify the traffic from the extension is from the extension and not some random request from anywhere (or an attacker)

Ok! So its better to use this token always!

So if I send this token,how can I validate that its secure? I think I saw a Validate request in the documentation