Обстоятельства ошибки "invalid_grant" при обновлении токена доступа?
В последнее время я вырывал свои волосы из-за этой проблемы.
Некоторый фон
- использование библиотеки oauth2client для управления токенами пользователей. Токены используются для периодического и одновременного выполнения различных фоновых задач.
- каждый раз, когда одна из этих задач собирается запускаться для пользователя, мы получаем объект Credentials из хранилища и выполняем обновление, если истекает срок действия ~5 минут. В противном случае текущий токен доступа используется повторно.
- бывает, что иногда несколько задач для одного пользователя выполняются одновременно
- какое-то время все работает нормально, токены обновляются нормально
- время от времени и, казалось бы, неожиданно, во время одной из этих попыток обновления возвращается ошибка "invalid_grant", которая полностью аннулирует маркер обновления в хранилище. (Когда / как / почему это происходит, я надеюсь выяснить этот вопрос)
Поиск вокруг, есть много тем / отчетов об этой проблеме. Но все, что я нашел до сих пор, не относится к нашему делу. Я постараюсь перечислить те, которые я изучал до сих пор:
- Пользователь отозвал разрешения
Этот является наиболее очевидным, наиболее документированным и легко воспроизводимым, но, к сожалению, в нашем случае наши пользователи (или мы сами во время тестирования) вообще не отзывали разрешения.
- Обновление "старого" токена доступа
Сначала я подумал, что для пользователя может быть только один действительный токен одновременно. Это неверно и подтверждено на OAuth2 Playground.
Существует ограничение в 25 активных токенов на пользователя на клиента. Как только этот предел достигнут, старые токены доступа автоматически становятся недействительными, даже если срок их действия еще не истек.
Это также тупик для нас, поскольку наша проблема возникает при обновлении, а не при использовании самого старого токена доступа. И это ограничение влияет только на токены доступа, но не на токены обновления.
- Запрос слишком много раз за короткий промежуток времени
Не документировано вообще. Только упомянуто мимоходом без ссылок. Пытался подражать ему, выполняя обновление 25 раз за 7 секунд, но все прошло хорошо. Но без ссылок, это выстрел в темноте. И наши фоновые задачи только максимум макс. ~10 задач каждые несколько минут. Двигаемся дальше.
- Одновременные обновления вызывают состояние гонки, при котором токен успешен
Я задал вопрос здесь, но это был не тот случай. Протестировано в AppEngine, запустив две задачи, запланированные одновременно.
Я нахожусь в конце своего остроумия, пытаясь определить эту проблему. Тот факт, что мы не можем легко воспроизвести это, является болью. Мне бы очень хотелось получить представление о том, что может быть причиной того, что я пропустил?
Вот наш код обновления:
def refresh_oauth_credentials(user, credentials, force=False):
if not credentials:
return None
logging.debug(credentials.token_expiry)
do_refresh = credentials._expires_in() < 300
if force or do_refresh:
h = httplib2.Http()
try:
logging.debug('Refreshing %s\'s oauth2 credentials...' % user.email)
credentials.refresh(h)
except AccessTokenRefreshError:
logging.warning('Failed to refresh.')
return None
return credentials
1 ответ
По сути, в сообщении говорится, что токен обновления либо недействителен (истек срок действия, отозван и т. Д.), Либо не соответствует деталям запроса токена доступа (пользователь, область действия). Таким образом, если в своем вопросе вы сказали, что "ошибка"invalid_grant"возвращена, и это полностью делает недействительным токен обновления в хранилище", то это как бы наоборот, т.е. токен обновления по какой-то причине недопустим, и это вызывает "недопустимое предоставление".
Я часто видел это во время разработки, если во время вашего рабочего процесса / тестирования разработчика вы получаете новые токены обновления для пользователя.