connect()
doesn't work.Twitch uses the IRC protocol as foundation for its chat. In this protocol, after connection, you must tell the server your name and (optionally) authenticate before you can send messages to channels.
The connect()
method will finish before that authentication step,
which in turn means that you can't join channels or send messages yet.
Instead, you should use the onAuthenticationSuccess
event to send messages.
chatClient.onAuthenticationSuccess(() => {
chatClient.say('someone', 'Hello, I\'m now connected!');
})
For joining channels, the channels
option exists in the constructor of the ChatClient
class.
You can even pass an async function to it to dynamically access a possibly changing set of channels:
const chatClient = new ChatClient({
authProvider,
channels: async () => await someDatabase.select('twitchUsername').from('users').fetchAll().map(u => u.twitchUsername)
})
EventSubMiddleware
show the error "The request body was already consumed by something else", and how do I fix it?This happens because you're using conflicting middleware that parses the body, such as:
body-parser
express.json()
express.raw()
Many popular express tutorials (in fact, even the official documentation of express
!)
tell you to apply these body parsers for all requests, like so:
const express = require('express');
const app = express();
app.use(express.json()); // don't do this!
app.get('/', (req, res) => res.send('Hello World'));
app.post('/echo-prop', (req, res) => res.send(req.body.prop));
app.listen(3000);
This code applies the JSON parser middleware for all requests.
That means that you have a JSON-parsed object in req.body
at all times.
Sadly, it also means that we can't read the raw body from the request anymore,
since it is already consumed by that middleware.
You might ask: "Why can't you just use req.body
if it already exists in a parsed form?"
The answer to this is that we need access to the raw body in order to match its signature.
In order to verify that the request really came from Twitch,
they sign the request using the secret that was passed at subscription time.
If we re-encode the JSON payload in req.body
rather than using the raw data,
the result might be slightly mismatched in formatting, which breaks the signature.
The proper way to use body parser middleware is to apply them where you actually expect JSON input (as opposed to returning JSON):
const express = require('express');
const app = express();
app.get('/', (req, res) => res.send('Hello World'));
app.post('/echo-prop', express.json(), (req, res) => res.send(req.body.prop));
app.listen(3000);
EventSubHttpListener
or EventSubMiddleware
starts up correctly, but it never tells me about successful subscriptions, why?This can have different reasons:
pathPrefix
to be stripped from the received URL.
Consult your reverse proxy's logs
and set up logging for the listener as well.subscription missing proper authorization
mean?If you're using @twurple/eventsub-ws
, your user token just doesn't have the
necessary scopes for the subscription.
@twurple/eventsub-http
on the other hand uses app tokens to create subscriptions. App tokens can't have any scopes.
However, that doesn't mean that authorization isn't necessary at all.
Twitch will check with its internal systems whether the user ever authorized the necessary scope for the topic
and give you the mentioned error message when it fails to find this authorization.
To get this authorization, simply go through OAuth (except the Client Credentials flow) with your client ID and the necessary scopes that are documented for your desired subscription topics. You can throw away the token you get from this. The authorization will still get saved on Twitch - now you can subscribe to your topics.