node.js oauth-1.0a работает для Twitter API v1.1, но не для v2

Я нашел эту функцию для создания заголовка oauth-1.0a:

// auth.js

const crypto = require("crypto");
const OAuth1a = require("oauth-1.0a");

function auth(request) {
  const oauth = new OAuth1a({
    consumer: {
      key: process.env.TWITTER_API_KEY,
      secret: process.env.TWITTER_API_SECRET_KEY,
    },
    signature_method: "HMAC-SHA1",
    hash_function(baseString, key) {
      return crypto.createHmac("sha1", key).update(baseString).digest("base64");
    },
  });

  const authorization = oauth.authorize(request, {
    key: process.env.TWITTER_ACCESS_TOKEN,
    secret: process.env.TWITTER_ACCESS_TOKEN_SECRET,
  });

  return oauth.toHeader(authorization).Authorization;
}

module.exports = auth;

Он отлично работает, если я попробую его с Twitter API v1.1:

// v1.js

require("dotenv").config();
const axios = require("axios");
const auth = require("./auth");

const url = "https://api.twitter.com/1.1/favorites/create.json";
const method = "POST";
const params = new URLSearchParams({
  id: "1397568983931392004",
});

axios
  .post(url, undefined, {
    params,
    headers: {
      authorization: auth({
        method,
        url: `${url}?${params}`,
      }),
    },
  })
  .then((data) => {
    return console.log(data);
  })
  .catch((err) => {
    if (err.response) {
      return console.log(err.response);
    }
    console.log(err);
  });

Но если я попробую это с Twitter API v2:

// v2.js

require("dotenv").config();
const axios = require("axios");
const auth = require("./auth");

const url = `https://api.twitter.com/2/users/${process.env.TWITTER_USER_ID}/likes`;
const method = "POST";
const data = {
  tweet_id: "1397568983931392004",
};

axios
  .post(url, data, {
    headers: {
      authorization: auth({
        method,
        url,
        data,
      }),
    },
  })
  .then((data) => {
    return console.log(data);
  })
  .catch((err) => {
    if (err.response) {
      return console.log(err.response);
    }
    console.log(err);
  });

это терпит неудачу с:

{
  title: 'Unauthorized',
  type: 'about:blank',
  status: 401,
  detail: 'Unauthorized'
}

Я попытался закодировать тело запроса, как было предложено здесь, но получаю ту же ошибку:

require("dotenv").config();
const axios = require("axios");
const auth = require("./auth");
const querystring = require("querystring");

const url = `https://api.twitter.com/2/users/${process.env.TWITTER_USER_ID}/likes`;
const method = "POST";
const data = percentEncode(
  querystring.stringify({
    tweet_id: "1397568983931392004",
  })
);

function percentEncode(string) {
  return string
    .replace(/!/g, "%21")
    .replace(/\*/g, "%2A")
    .replace(/'/g, "%27")
    .replace(/\(/g, "%28")
    .replace(/\)/g, "%29");
}

axios
  .post(url, data, {
    headers: {
      "content-type": "application/json",
      authorization: auth({
        method,
        url,
        data,
      }),
    },
  })
  .then((data) => {
    return console.log(data);
  })
  .catch((err) => {
    if (err.response) {
      return console.log(err.response);
    }
    console.log(err);
  });

При тестировании с Postman обе конечные точки (1.1 и 2) работают нормально с одинаковыми учетными данными.

Любые идеи о том, что я делаю неправильно при использовании v2 или как заставить его работать с Twitter API v2?

Я подозреваю, что это связано с телом запроса, поскольку это основное различие между обоими запросами, но я не смог заставить его работать.


person MauricioRobayo    schedule 10.07.2021    source источник
comment
Является ли ваше приложение частью проекта с доступом к API v2?   -  person Andy Piper    schedule 10.07.2021
comment
Да, я проверил с почтальоном и работает, как V1.1, так и V2, но так не работает и хочу разобраться.   -  person MauricioRobayo    schedule 10.07.2021


Ответы (1)


Разберитесь, тело запроса не должно включаться при генерации заголовка авторизации:

require("dotenv").config();
const axios = require("axios");
const auth = require("./auth");

const url = `https://api.twitter.com/2/users/${process.env.TWITTER_USER_ID}/likes`;
const method = "POST";
const data = {
  tweet_id: "1397568983931392004",
};

axios
  .post(url, data, {
    headers: {
      authorization: auth({
        method,
        url,
      }),
    },
  })
  .then((data) => {
    return console.log(data);
  })
  .catch((err) => {
    if (err.response) {
      return console.log(err.response);
    }
    console.log(err);
  });

По сути, при отправке почтового запроса в Twitter API v1.1 данные должны быть закодированы, должны использоваться для генерации заголовка авторизации, а почтовый запрос должен быть отправлен как application/x-www-form-urlencoded.

При отправке почтового запроса в Twitter API v2 данные не должны быть закодированы, не должны включаться при создании заголовка авторизации и должны отправляться как application/json.

Надеюсь, это станет полезным для кого-то еще.

person MauricioRobayo    schedule 11.07.2021