Ошибка Tweepy .get_me() при использовании потока OAuth 2.0 User Auth с PKCE
Попытка получить идентификатор Twitter ID и имя пользователя Twitter аутентифицированного пользователя с помощью пакета Tweepy. С аутентификацией через поток OAuth 2.0 (используя представление Django). Мне удалось создать экземпляр класса Client пакета Tweepy pkg с помощью потока OAuth 2.0 User Context, но когда я использую метод .get_me(), я получаю ошибку.
Ошибка: "Потребительский ключ должен быть строкой или байтом, а не NoneType"
Ошибка предполагает, что метод требует Ключ потребителя, но в данном случае я инициализировал класс, используя поток OAuth 2.0 User Context с PKCE, который не требует этого.
Я создал экземпляр с помощью приведенного ниже фрагмента (так, как это указано в документации Tweepy здесь):
import tweepy
oauth2_user_handler = tweepy.OAuth2UserHandler(
client_id="Client ID here",
redirect_uri="Callback / Redirect URI / URL here",
scope=["follows.read", "users.read", "tweet.read", "offline.access"],
client_secret="Client Secret here"
)
access_token = oauth2_user_handler.fetch_token(
"Authorization Response URL here"
)
client = tweepy.Client("Access Token here")
Объект Client не кажется проблемой, поскольку я перенаправляюсь в Twitter для авторизации и перенаправляюсь обратно через обратный вызов, как это и должно работать. Ключ потребителя является требованием потока OAuth 1.0 User Context, но это не то, что я хотел инициализировать здесь.
Вот метод get_me() из файла client.py в Tweepy pkg:
def get_me(self, *, user_auth=True, **params):
"""get_me(*, expansions=None, tweet_fields=None, user_fields=None, \
user_auth=True)
Returns information about an authorized user.
.. versionadded:: 4.5
Parameters
----------
expansions : list[str] | str | None
:ref:`expansions_parameter`
tweet_fields : list[str] | str | None
:ref:`tweet_fields_parameter`
user_fields : list[str] | str | None
:ref:`user_fields_parameter`
user_auth : bool
Whether or not to use OAuth 1.0a User Context to authenticate
Returns
-------
dict | requests.Response | Response
References
----------
https://developer.twitter.com/en/docs/twitter-api/users/lookup/api-reference/get-users-me
"""
return self._make_request(
"GET", f"/2/users/me", params=params,
endpoint_parameters=("expansions", "tweet.fields", "user.fields"),
data_type=User, user_auth=user_auth
)
# Search Spaces
Я попробовал передать необходимые теги OAuth 1.0 (Bearer Token, Consumer Key, Consumer Secret, Access Token и Access Secret) при создании экземпляра Client для тестирования, и это заставило метод работать так, как он должен. При тестировании я установил для Bearer Token значение "access_token", указанное выше. Однако это противоречит цели, поскольку у меня не будет access_token и access_token_secret от внешних пользователей (я смог получить их для своего собственного аккаунта через Twitter Dev Portal).
Пробовал также установить параметр user_auth в false при вызове метода, но это вызывает ошибку 403 Forbidden, "Аутентификация с помощью OAuth 2.0 Application-Only запрещена для этой конечной точки. Поддерживаются следующие типы аутентификации [OAuth 1.0a User Context, OAuth 2.0 User Context]."
Вопрос заключается в методе? Или я что-то упускаю?
Документация Tweepy для метода .get_me(): https://docs.tweepy.org/en/stable/client.html#tweepy.Client.get_me
Источник для класса Client & метод get_me() в репозитории Tweepy: https://github.com/tweepy/tweepy/blob/master/tweepy/client.py
Документация API Twitter для GET /2/users/me: https://developer.twitter.com/en/docs/twitter-api/users/lookup/api-reference/get-users-me
Эту проблему для меня решил контрибьютор проекта, Harmon758, здесь.
Решение требовало двух вещей. Во-первых, установить параметр user_auth в значение False при вызове метода .get_me(). Это необходимо сделать, поскольку функция по умолчанию использует OAuth 1.0, если это не так.
Во-вторых, чтобы обойти ошибку 401 unauthorized, упомянутую в комментарии, мне нужно было изменить формат маркера доступа, который я передавал объекту Client. Я пытался передать 'access_token' в приведенном выше коде, но это должно было быть 'access_token["access_token"]'. Возвратом метода .fetch_token() является словарь, содержащий требуемое поле.
Правильный код:
Построить обработчик с:
oauth2_user_handler = tweepy.OAuth2UserHandler(
client_id='your_client_id',
redirect_uri="your_redirect_uri",
scope=["tweet.read", "and any others you need"],
# Client Secret is only necessary if using a confidential client
client_secret='your_client_secret'
)
Перенаправление в Twitter для авторизации с помощью:
def auth(request):
return HttpResponseRedirect(oauth2_user_handler.get_authorization_url())
И, наконец, обратный вызов:
def callback(request):
access_token = oauth2_user_handler.fetch_token(request.build_absolute_uri())
user_client = tweepy.Client(
access_token["access_token"]
)
me = user_client.get_me(user_auth=False)
return HttpResponse()