oskar.makarov
портфолио / apple secret · разбор ошибки
разбор · вход через apple

Вход через Apple сломался с invalid_client

Работало месяцами, ничего не выкатывали, и внезапно никто не может войти. Если вашему входу через Apple около полугода — это почти наверняка ваш случай.

Как это выглядит

Сервер Apple перестаёт принимать ваше приложение и отвечает коротким JSON. На вашей стороне при этом не менялось ничего:

HTTP 400 · https://appleid.apple.com/auth/token
{"error":"invalid_client"}

Пользователь видит другое: кнопка Apple не делает ничего либо возвращает на экран входа без сообщения. В логах — тот же invalid_client.

Почему так происходит

В отличие от всех остальных OAuth-провайдеров, у Apple нет долгоживущего секрета. То, что вы вставили в бэкенд или в Supabase, — это JWT, который вы подписали сами, и Apple ограничивает его срок примерно шестью месяцами: 15777000 секунд — задокументированный максимум.

Предупреждений Apple не присылает. Ни письма, ни баннера в консоли, ни отметки в дашборде. Секрет просто перестаёт быть валидным, и первыми об этом узнают ваши пользователи.

Официальная документация Supabase прямо советует «поставить повторяющееся напоминание в календаре раз в полгода». Это текущее состояние индустрии.

Убедиться, что дело именно в этом

Ваш client secret — это JWT: три блока base64 через точку. Раскодируйте средний и посмотрите на поле exp, это метка времени Unix.

  1. Возьмите секрет из конфига бэкенда или из настроек провайдера Apple в Supabase
  2. Раскодируйте payload: любым декодером JWT или base64 по среднему сегменту
  3. exp в прошлом — это ваш случай. exp в будущем — причина другая: не тот Services ID, не тот Team ID или несовпадение redirect URI.

Что Apple ждёт внутри этого JWT

Пригодится, когда будете пересобирать секрет руками: неверное поле даёт ровно ту же ошибку invalid_client, из-за чего её так тяжело диагностировать.

algES256, другой алгоритм Apple не примет
kidKey ID вашего ключа .p8
issваш Apple Team ID
subServices ID, а не bundle ID приложения
audhttps://appleid.apple.com
expне дальше чем iat + 15777000 секунд

Починить прямо сейчас, руками

  1. Откройте портал разработчика Apple → Certificates, Identifiers & Profiles → Keys и найдите ключ, созданный для Sign in with Apple. Нужны его Key ID и файл .p8. Если .p8 потерян — создайте новый ключ: Apple даёт скачать файл только один раз.
  2. Team ID возьмите в правом верхнем углу портала, Services ID — в разделе Identifiers. Он выглядит как домен наоборот и это не bundle ID вашего приложения.
  3. Соберите новый JWT с алгоритмом ES256 и полями из таблицы выше. exp ставьте не дальше полугода.
  4. Вставьте новый секрет туда, где лежал старый: конфиг бэкенда либо Supabase → Authentication → Providers → Apple → Secret Key.
  5. Войдите один раз для проверки. Ошибка исчезает сразу, ждать распространения и чистить кеш не нужно.

Это вся починка. Занимает минут десять и покупает вам полгода.

Через полгода повторится

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

Либо перестать делать это руками

Я напоролся на это на своём проекте и написал бесплатный GitHub Action. По расписанию он пересобирает JWT из вашего .p8 и записывает его в Supabase через Management API. Не Supabase? Он просто отдаёт свежий секрет как output — заберите куда нужно. MIT, ноль зависимостей, вся логика в одном читаемом файле.

Открыть инструмент → бесплатно · MIT · запускается раз в 5 месяцев, месяц запаса

Частые вопросы

Можно поставить срок побольше и забыть?

Нет. Полгода — жёсткий потолок Apple. JWT с большим exp отклоняется сразу, и вы получите тот же invalid_client не через полгода, а немедленно.

Перевыпуск секрета разлогинит пользователей?

Нет. Client secret удостоверяет ваш сервер перед Apple, а не пользователя перед вами. Действующие сессии не затрагиваются.

Я потерял файл .p8. Это фатально?

Нет, но восстановить его нельзя: Apple разрешает одно скачивание. Создайте новый ключ в портале, запишите его новый Key ID и пересоберите секрет с новой парой.

Почему invalid_client вылезает и на свежем секрете?

Потому что Apple отдаёт одну и ту же ошибку на несколько разных причин: bundle ID вместо Services ID в поле sub, не тот Team ID в iss, алгоритм отличный от ES256, несовпадение redirect URI. Поэтому и стоит начинать с проверки exp — она сразу отсекает половину вариантов.

Поставьте один раз —
и забудьте.

Взять в GitHub Marketplace → бесплатно · MIT · ноль зависимостей · настройка один раз
© 2026 Oskar Makarov ▍apple-client-secret-rotator · MIT