Ошибка invalid_grant при авторизации через Apple ID (iOS, бекенд)

20 ноября 2020

Реализовывал я вход через Apple ID в одном приложении на Flutter, а бекенд был на Laravel. Научили приложение генерировать токен, отправляли токен в бекенд, бекенд проверял его у Эпл, а Эпл в ответ присылал invalid_grant.

0. Вводная, настройка входа через Apple ID

Вся настройка занимает несколько шагов, после которых мы получаем настройки и используем их в приложении и в коде бекенда. Что за шаги? Поехали:

  1. Генерируем App ID
  2. Генерируем Service ID
  3. Создаём приватный ключ Private Key
  4. Генерируем clientSecret на основе данных из шагов 1−3

Подробное описание шагов доступно, например, в репозитории одной из библиотек для Laravel.

На выходе у нас есть самое важное: clientId и clientSecret, которые мы используем и внутри приложения, и внутри нашего бекенда.

С подготовкой закончили. Теперь вернёмся к нашей ошибке invalid_grant.

1. Смотрим документацию

Документация Эпл говорит следующее:

The authorization grant or refresh token is invalid, typically due to a mismatched or invalid client identifier, invalid code (expired or previously used authorization code), or invalid refresh token.

То есть что-то не так с токеном, которое нам отдало приложение. Идём проверять, действительно ли что-то не так с этим кодом.

2. Проверяем явные ошибки: повторные запросы, «протухание» кода

Когда Эпл отдаёт нам в приложении authCode, то мы отправляем его в бекенд, а бекенд уже с этим кодом запрашивает у Эпл данные о пользователе. Тут может возникнуть несколько проблем:

  1. Вы как-то не так отправляете код в бекенд: он как-нибудь конкатенируется или парсится из json криво, приходит не в том формате. Обычно это редкость, но всё же стоит проверить.
  2. Токен успевает протухнуть. Это редкость, потому что токен живёт 5 минут, вряд ли у вас запрос между приложением и бекендом ходит больше 5 минут. Но имейте ввиду.
  3. Проблема почаще: наличие повторных запросов. Например, вы в коде через провайдер получаете данные о пользователе, а потом логините его через этот же провайдер. В обоих методах провайдер шлёт запрос в Эпл, и на второй запрос authCode протухает.

Исключаем всё это, но ошибка всё ещё появляется. Что делать? Мы попробовали перегенерировать clientId и clientSecret, но это не помогло. Продолжаем гуглить.

3. Пробуем заменить Service ID на App ID

Находим кое-что! Удалось найти интересное описание проблемы в одном из репозиториев node. js-библиотек для входа через Apple ID:

invalid_grant when authorization code is generated by iOS App
Fix: If the authorizationCode was generated by your app, you should use your App ID as your clientId and not your service one. Discussion: https://github.com/ananay/apple-auth/issues/13

То есть если мы генерируем токен в приложении, то в качестве clientId нужно использовать App ID, а не Service ID. При этом почти везде все пишут, что в качестве clientId нужно использовать именно Service ID.

Wat" by Meme Economy | Redbubble
Моё лицо после изучения этого кейса

Выходит, если у нас меняется clientId, то нужно перегенрировать и clientSecret, потому что он напрямую зависит от clientId. Генерируем заново. Прописываем новый clientId в приложении, а также новые clientId и clientSecret в бекенде.

Это сработало! 🎉

Добавить комментарий