Ошибка 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()
Вернуться на верх