Moderator_id error

Can you tell me what could be the error in the ban function? Error: The ID in moderator_id must match the user ID found in the request’s OAuth token.
When checking the OAuth token moderator_id is matched to the user ID found in the request.
Script:
const tmi = require(‘tmi.js’);
const axios = require(‘axios’);
const dotenv = require(‘dotenv’);
const express = require(‘express’);
const qs = require(‘qs’);

require(‘dotenv’).config();

const app = express();
const port = 3000;

// Конфигурация бота
const channels = [‘valyoko’, ‘dankzlv’, ‘vitollo_13’, ‘tadzheek’, ‘steel’, ‘ravshann’, ‘renatko’, ‘dedadam’];
const botConfigs = channels.map((channel) => {
return {
options: { debug: true },
identity: {
username: ‘valyoko’,
password: process.env.TWITCH_OAUTH_TOKEN,
},
channels: [channel]
};
});

// Создание клиентов TMI.js для каждого канала
const clients = botConfigs.map((config) => {
const client = new tmi.client(config);

client.on(‘join’, (channel, username, self) => {
if (self && channel.slice(1) === ‘valyoko’) {
console.log(Бот успешно подключился к каналу ${channel});
client.say(channel, ‘Бот успешно подключился’);
} else if (self) {
const valyokoClient = clients.find((c) => c.getChannels()?.[0]?.slice(1) === ‘valyoko’);
if (valyokoClient) {
valyokoClient.say(‘valyoko’, Бот подключился к каналу ${channel});
}
}
});

client.connect()
.catch((error) => {
console.log(Ошибка подключения к каналу ${config.channels[0]}: ${error});
});

return client;
});

// Настройки Twitch API
const clientId = process.env.TWITCH_CLIENT_ID;
const clientSecret = process.env.TWITCH_CLIENT_SECRET;
const redirectUri = ‘http://localhost:3000/auth/twitch/callback’;
const scopes = ‘moderator:manage:banned_users’;
const authorizationUrl = https://id.twitch.tv/oauth2/authorize?client_id=${clientId}&redirect_uri=${redirectUri}&response_type=code&scope=${scopes};

// Переменные для хранения токена доступа и времени его получения
let accessToken = null;
let tokenExpiration = 0;

// Обработчик GET-запроса на страницу авторизации Twitch
app.get(‘/auth/twitch’, (req, res) => {
res.redirect(authorizationUrl);
});

// Обработчик GET-запроса на обратный вызов Twitch
app.get(‘/auth/twitch/callback’, async (req, res) => {
const code = req.query.code;

try {
// Получаем токен доступа с помощью кода авторизации
const tokenResponse = await exchangeCodeForToken(code);

accessToken = tokenResponse.access_token;
const expiresIn = tokenResponse.expires_in;
// Устанавливаем время истечения токена на будущее с учетом смещения
tokenExpiration = Date.now() + expiresIn * 1000;

console.log(`Токен доступа успешно обновлен на ${accessToken}`);
res.send('Токен доступа успешно получен. Можете закрыть это окно.');

} catch (error) {
console.log(Ошибка при получении токена доступа: ${error.response.data.message});
res.status(500).send(‘Произошла ошибка при получении токена доступа.’);
}
});

// Функция для обмена кода авторизации на токен доступа
async function exchangeCodeForToken(code) {
const tokenUrl = https://id.twitch.tv/oauth2/token;

try {
const response = await axios.post(tokenUrl, null, {
params: {
client_id: clientId,
client_secret: clientSecret,
code: code,
grant_type: ‘authorization_code’,
redirect_uri: redirectUri
}
});

return response.data;

} catch (error) {
console.log(Ошибка при обмене кода авторизации на токен доступа: ${error});
throw error;
}
}

// Функция для проверки и обновления токена доступа
async function checkAndUpdateToken() {
// Проверяем, есть ли у нас действующий токен или он истек
if (!accessToken || tokenExpiration <= Date.now()) {
await getAccessToken();
}
}

// Функция для получения токена доступа
async function getAccessToken() {
const tokenUrl = https://id.twitch.tv/oauth2/token;

try {
const response = await axios.post(
tokenUrl,
qs.stringify({
client_id: clientId,
client_secret: clientSecret,
grant_type: ‘client_credentials’,
scope: scopes
}),
{
headers: {
‘Content-Type’: ‘application/x-www-form-urlencoded’
}
}
);

accessToken = response.data.access_token;
const expiresIn = response.data.expires_in;
// Устанавливаем время истечения токена на будущее с учетом смещения
tokenExpiration = Date.now() + expiresIn * 1000;

console.log(`Токен доступа успешно получен и установлен на ${accessToken}`);

} catch (error) {
console.log(Ошибка при получении токена доступа: ${error.response.data.message});
throw error;
}
}

// Функция для выполнения бана пользователя через Twitch API
async function banUser(username, reason) {
const moderatorId = ‘90670041’;

try {
if (!moderatorId) {
console.log(Ошибка при бане пользователя: Не указан moderatorId);
return;
}

for (let i = 0; i < clients.length; i++) {
  const client = clients[i];
  const channel = client.getChannels()?.[0]?.slice(1);
  if (!channel) {
    console.log(`Ошибка при бане пользователя: Клиент не подключен к каналу`);
    continue;
  }

  await checkAndUpdateToken(); // Обновляем токен доступа

  const clientId = process.env.TWITCH_CLIENT_ID;
  const broadcasterId = process.env[`TWITCH_BROADCASTER_ID_${channel.toUpperCase()}`]; // Получаем идентификатор канала (broadcast_id)
  const userId = await getUserId(username, accessToken, clientId);

  if (!userId) {
    console.log(`Ошибка при бане пользователя: Пользователь ${username} не найден`);
    continue;
  }

  const url = `https://api.twitch.tv/helix/moderation/bans?broadcaster_id=${broadcasterId}&moderator_id=${moderatorId}`;
  const headers = {
    'Authorization': `Bearer ${accessToken}`,
    'Client-Id': clientId,
    'Content-Type': 'application/json'
  };
  const data = {
    data: {
      user_id: userId,
      reason: reason || 'No reason provided'
    }
  };

  await axios.post(url, data, { headers });

  // Добавляем паузу в 1 секунду между отправкой сообщений в чат разных каналов
  await sleep(1000);

  const valyokoClient = clients.find((c) => c.getChannels()?.[0]?.slice(1) === 'valyoko');
  if (valyokoClient) {
    valyokoClient.say('valyoko', `${username} был забанен на канале ${channel}. Причина: ${reason}`);
  }
}

} catch (error) {
console.log(Ошибка при бане пользователя: ${error.response.data.message});
}
}

// Функция для выполнения разбана пользователя через Twitch API
async function unbanUser(username) {
const moderatorId = ‘90670041’;

try {
if (!moderatorId) {
console.log(Ошибка при разбане пользователя: Не указан moderatorId);
return;
}

for (let i = 0; i < clients.length; i++) {
  const client = clients[i];
  const channel = client.getChannels()?.[0]?.slice(1);
  if (!channel) {
    console.log(`Ошибка при разбане пользователя: Клиент не подключен к каналу`);
    continue;
  }

  await checkAndUpdateToken(); // Обновляем токен доступа

  const clientId = process.env.TWITCH_CLIENT_ID;
  const broadcasterId = process.env[`TWITCH_BROADCASTER_ID_${channel.toUpperCase()}`]; // Получаем идентификатор канала (broadcast_id)
  const userId = await getUserId(username, accessToken, clientId);

  if (!userId) {
    console.log(`Ошибка при разбане пользователя: Пользователь ${username} не найден`);
    continue;
  }

  const url = `https://api.twitch.tv/helix/moderation/bans?broadcaster_id=${broadcasterId}&user_id=${userId}&moderator_id=${moderatorId}`;
  const headers = {
    'Authorization': `Bearer ${accessToken}`,
    'Client-Id': clientId
  };

  await axios.delete(url, { headers });

  // Добавляем паузу в 1 секунду между отправкой сообщений в чат разных каналов
  await sleep(1000);

  const valyokoClient = clients.find((c) => c.getChannels()?.[0]?.slice(1) === 'valyoko');
  if (valyokoClient) {
    valyokoClient.say('valyoko', `${username} был разбанен на канале ${channel}`);
  }
}

} catch (error) {
console.log(Ошибка при разбане пользователя: ${error.response.data.message});
}
}

// Функция для получения User ID пользователя или канала
async function getUserId(username, accessToken, clientId) {
try {
const response = await axios.get(https://api.twitch.tv/helix/users?login=${username}, {
headers: {
‘Authorization’: Bearer ${accessToken},
‘Client-Id’: clientId
}
});

const userData = response.data.data[0];

if (!userData) {
  console.log(`Пользователь ${username} не найден`);
  return null;
}

const userId = userData.id;
return userId;

} catch (error) {
console.log(Ошибка при получении User ID для пользователя ${username}: ${error.response.data.message});
return null;
}
}

// Функция для добавления паузы
function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}

// Обработка сообщений чата
clients.forEach((client) => {
client.on(‘message’, (channel, userstate, message, self) => {
if (message.toLowerCase().startsWith('!ban ‘) && userstate.username.toLowerCase() === ‘valyoko’) {
const params = message.slice(5).trim().split(’ ‘);
const bannedUser = params[0];
const reason = params.slice(1).join(’ ‘);
banUser(bannedUser, reason);
} else if (message.toLowerCase().startsWith(’!unban ') && userstate.username.toLowerCase() === ‘valyoko’) {
const unbannedUser = message.slice(7).trim();
unbanUser(unbannedUser);
}
});
});

Token validation
image

You appear to be overwriting your accessToken variable with an App Access token. These tokens represent an App, not a user, thus they don’t have a user id nor scopes, so while at some point your accessToken may have the correct token, you’re overwriting it with the wrong one.

Also,

It’s quite excessive to create a separate connection for each individual channel, and provides no benefit to you as the rate limits are shared across all connections for that account. You should just use 1 connection and have it join all the channels.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.