24 августа 2026 года Apple объявила, что новые адреса Private Relay для Sign in with Apple будут выпускаться на домене private.icloud.com. Ранее выпущенные адреса с доменом privaterelay.appleid.com продолжат работать и пересылать почту без перерыва.
На уровне почтовой доставки это выглядит как обычная смена суффикса. Первая мысль тоже была простой: надо проверить allowlist, если он вдруг есть. Но за этой деталью скрывается более важный вопрос: что именно приложение считает личностью пользователя после входа через Apple?
Я решил пройтись по собственной схеме авторизации. В результате проверка домена оказалась наименее интересной частью. Полезнее было еще раз отделить три сущности, которые часто случайно склеивают в одну: доказательство входа, стабильную идентичность и адрес для связи.

Ниже не инструкция по подключению кнопки Sign in with Apple. Речь о более приземленной задаче: как пережить изменение вокруг Private Relay без миграции аккаунтов, случайных дублей и автоматического склеивания чужих профилей.
Что именно меняется
Private Relay позволяет пользователю скрыть свой настоящий адрес. Приложение получает специальный адрес, а Apple пересылает на него письма на реальный почтовый ящик пользователя. Для приложения это нормальный адрес доставки, но не доказательство того, что оно знает постоянный email человека.
Apple сообщает, что новые адреса Private Relay позднее в 2026 году будут использовать домен private.icloud.com. Уже созданные адреса с privaterelay.appleid.com не требуют замены и продолжают пересылать почту. Это не повод переписывать записи пользователей в базе и не сигнал, что старые адреса стали невалидными.
При этом принятый адрес еще не равен гарантированной доставке. Для отправки через Private Relay нужно корректно настроить и зарегистрировать отправляющую почтовую инфраструктуру, а пользователь может отключить пересылку. Это состояние канала связи, которое почтовой подсистеме важно учитывать отдельно от идентичности аккаунта.
Риск появляется только там, где домен email незаметно стал частью бизнес-логики. Например:
Валидация принимает только
privaterelay.appleid.com.Правила доставки или suppression-list делят Apple Relay на «настоящий» и «подозрительный» адрес только по домену.
Поддержка ищет аккаунт исключительно по email и не видит provider identity.
Новый вход пытается автоматически объединить аккаунты по совпавшему или похожему адресу.
Смена домена хорошо подсвечивает проблему, но не создает ее. Если от суффикса email зависит право войти, выбрать существующий аккаунт или связать две учетные записи, архитектура была хрупкой и до этого обновления.
Email - это контакт, а не ключ аккаунта
У обычной почтовой регистрации соблазн понятен: человек вводит email и пароль, поэтому email кажется естественным ключом. Но даже в таком случае это плохая модель для всего продукта. Пользователь может сменить адрес, потерять доступ к ящику или использовать один адрес в нескольких независимых контекстах.
В Sign in with Apple это заметнее. Apple возвращает объект с запрошенными именем и email только при первом согласии пользователя. В последующих ответах email может присутствовать как claim подписанного identity token, но имя и сам user-объект уже не возвращаются. Кроме того, у managed Apple Account email claim может быть пустым. Поэтому повторный вход должен работать по проверенной identity, а не зависеть от того, какое именно поле с адресом пришло в конкретном ответе.
Поэтому полезно держать такую границу:
Сущность |
Для чего нужна |
Что нельзя из нее выводить |
|---|---|---|
Подписанный identity token |
Доказать, что запрос действительно выдан Apple для ожидаемого приложения |
Что любой claim можно принять без проверки подписи, |
|
Связать конкретную Apple identity с внутренним аккаунтом |
Что это почтовый адрес или публичный профиль человека |
Email, включая Private Relay |
Доставить письмо, если пользователь его разрешил |
Что это постоянный идентификатор, общий ключ для склейки аккаунтов или доказательство владения другой учетной записью |
Самое важное следствие: отсутствие email в пользовательском объекте или пустой email claim не должны создавать новый аккаунт и не должны ломать повторный вход.
Устойчивый ключ - provider и subject
В моем случае сервер получает от клиента identity token, authorization code и nonce. Он не доверяет полям из интерфейса как факту идентичности: сначала проверяет подпись Apple, issuer, audience, срок действия и nonce, затем получает подтвержденный subject.
Дальше в базе живет отдельная запись identity:
auth_identities provider = "apple" subject = verifiedToken.sub account_id = internalAccountID unique(provider, subject)
Пара provider + subject однозначно выбирает внутренний аккаунт. Email не участвует в этом запросе. Если та же Apple identity войдет еще раз, сервер найдет существующую запись по provider и subject, обновит необходимое провайдерское состояние и выпустит новую сессию для того же account_id.

Это не означает, что sub можно принимать в виде строки, присланной мобильным клиентом. Его ценность появляется только после полной серверной проверки токена. Проверять хотя бы подпись недостаточно: токен должен быть выдан ожидаемым issuer, предназначен для ожидаемого client ID, не просрочен, а nonce должен совпасть с заранее созданным значением для конкретной попытки входа. После успешной проверки этот nonce нужно считать использованным, иначе он не защищает от повторного воспроизведения запроса.
Я также храню provider отдельно от subject. Сегодня это Apple, завтра может появиться другой вход. У разных провайдеров одинаковая строка subject не должна означать одного и того же пользователя.
Есть важная граница этого правила. Apple документирует свой user identifier как уникальный и стабильный внутри developer team. Если приложение передают другой team, это отдельный migration flow с transfer_sub, а не обычный повторный вход. Apple ограничивает этот переходный период 60 днями, поэтому его нужно планировать отдельно. В этой статье речь только о нормальном сценарии внутри одной команды.
Четыре решения, которые кажутся удобными
С технической точки зрения ошибка редко выглядит как явное if email.endsWith(...). Чаще она прячется в безопасном на вид упрощении.
1. Искать Apple-аккаунт по email
account = accounts.find(email: token.email)
Такая логика ставит поиск аккаунта в зависимость от email. Но пользовательский объект Apple приходит только при первом согласии, а email claim в отдельных сценариях может быть пустым. Хуже того, этот подход смешивает Apple identity с уже существующей email-учетной записью. Одно совпадение адреса не доказывает, что эти способы входа должен связывать сервер.
2. Хранить в базе только email
Если в модели нет provider и subject, то повторный вход без нового пользовательского объекта превращается в исключение, которое начинают чинить эвристиками. Обычно после этого появляются дубли, служебные флаги и ручные операции в поддержке.
3. Узнавать Private Relay по одному домену
После новости Apple такой код особенно заметен:
isAppleRelay = email.hasSuffix("@privaterelay.appleid.com")
Проверка перестает видеть новые адреса. Но расширить ее еще одним суффиксом - лишь временная заплатка. Сам факт, что приложению нужно принимать решение об идентичности по relay-домену, обычно говорит о неправильной границе данных.
4. Автоматически объединять аккаунты при «похожем» email
Так можно случайно связать независимую почтовую регистрацию и Apple identity. Корректнее делать linking отдельным явным сценарием: пользователь должен пройти свежую авторизацию обоими способами и подтвердить намерение. Адрес из claim или профиля сам по себе для этого недостаточен.

Как я бы провел аудит за один рабочий день
Полная переработка авторизации для такого изменения не нужна. Достаточно пройти по точкам, где email мог стать неявным ключом.
1. Модель данных и уникальные индексы
Нужна отдельная таблица или эквивалентная сущность для внешних identity. На паре (provider, subject) должен быть уникальный индекс. Он важен не только для порядка в данных, но и для гонки: два почти одновременных первых входа не должны создать два аккаунта.
Создание внутреннего аккаунта и identity нужно поместить в одну транзакцию, чтобы проигравшая гонку попытка не оставила orphan account. В обработчике ошибки уникальности стоит еще раз прочитать уже созданную identity и вернуть ее аккаунт. Это надежнее, чем надеяться, что два HTTP-запроса не пересекутся во времени.
2. Граница проверки токена
Проверка Apple должна завершаться объектом вроде VerifiedAppleIdentity, в котором уже есть только подтвержденные данные, нужные домену. Внутренний сервис авторизации не должен разбирать JWT, ходить за ключами Apple или доверять данным из UI.
Так проще писать тесты и несложно увидеть границу ответственности:
mobile client -> sends credentials Apple adapter -> verifies token and code -> returns verified provider + subject auth service -> resolves internal account -> creates session
3. Все места, где трогают email
Поискать стоит не только в endpoint входа. Я бы проверил:
нормализацию и валидацию адреса;
доменные allowlist и denylist;
отправку транзакционных писем и обработку bounce;
поиск в админке и инструментах поддержки;
антифрод, rate limit и аналитику;
логи, ошибки и трассировки;
сценарий удаления аккаунта и повторной авторизации.
Цель не в том, чтобы запретить упоминать Private Relay. Цель в том, чтобы только почтовая подсистема работала с адресом как с адресом, а авторизация работала с проверенной provider identity.
4. Логи и приватность
Identity token, authorization code и refresh token не должны попадать в логи. Для технической диагностики достаточно внутреннего ID аккаунта и, при реальной необходимости, хеша provider subject с ограниченным сроком хранения. Сам sub тоже не нужно без причины развозить по аналитическим системам.
Полезно заранее ответить и на вопрос об удалении. Если пользователь отозвал согласие или удалил аккаунт, нельзя оставлять провайдерские токены «на всякий случай». Но удаление токена не обязательно означает, что надо потерять данные, требуемые для корректной будущей явной повторной авторизации. Это отдельная политика жизненного цикла, а не следствие смены relay-домена.
Тесты, которые переживут следующее изменение Apple
Не стоит строить тест вокруг конкретного суффикса. Лучше зафиксировать поведение системы.
Сценарий |
Ожидаемый результат |
|---|---|
Первый вход с проверенным |
Создается один внутренний аккаунт и identity |
Повторный вход с тем же |
Открывается тот же аккаунт |
Два параллельных первых входа с одним |
В базе остается один аккаунт и одна identity |
Email с |
Используется только как адрес связи, если он передан |
Email с |
Ведет себя так же, без специальной ветки авторизации |
Токен с неверным |
Вход отклоняется до работы с аккаунтом |
Совпадающий email у другой учетной записи |
Аккаунты не объединяются автоматически |

Отдельный unit-тест на оба домена все равно полезен, если в продукте есть отправка писем, правила bounce или список разрешенных адресов. Но он должен тестировать именно почтовую интеграцию. В auth-тестах главными остаются provider, подтвержденный sub и проверка токена.
Что делать, если в системе уже есть email как ключ
Если Apple-вход уже связали с email, я бы не начинал с массового скрипта миграции. Сначала стоит остановить появление новой некорректной связи:
Добавить явную модель внешней identity и уникальность
provider + subject.Сохранять subject после успешной серверной проверки токена.
Для повторного входа сначала искать identity, а не email.
Запретить автоматическое linking по email.
Отдельно разобрать конфликтные записи и решить, какой явный сценарий подтверждения подойдет пользователю.
Только после этого можно оценивать старые данные. Иногда достаточно добавить недостающую identity при следующем успешном входе. Иногда потребуется ручной или подтверждаемый пользователем flow. Автоматический merge удобен для команды, но цена ошибки - доступ к чужому аккаунту.
Вывод
Изменение домена Private Relay не требует паники и не требует переписывать все адреса в базе. Оно просто хорошо проверяет, не сделали ли мы email фундаментом идентичности.
Устойчивое правило получилось коротким: Apple доказывает вход подписанным токеном, сервер извлекает из него проверенный subject, а внутренний аккаунт связывается с парой provider + subject. Email остается важным, но выполняет свою обычную роль - канал связи.
Если эта граница выдержана, появление private.icloud.com проходит как обычное изменение в почтовой интеграции. Если нет, новость Apple полезна тем, что обнаружила архитектурный долг до того, как его заметят пользователи.