Как на PHP реализовать авторизацию через Sign In with Apple с проверкой id_token на сервере?

Авторизация через Sign In with Apple на PHP требует нескольких шагов: получения id_token от клиента, его верификации на сервере и идентификации пользователя. Разберём процесс подробно.

**1. Как работает Sign In with Apple**
После успешной авторизации на клиенте (iOS, Web) Apple возвращает id_token — JWT-токен, подписанный приватным ключом Apple. Задача сервера — проверить подпись этого токена и извлечь данные пользователя.

**2. Установка зависимостей**
Для работы с JWT на PHP используйте библиотеку firebase/php-jwt:

composer require firebase/php-jwt

**3. Получение публичных ключей Apple**
Apple публикует публичные ключи по адресу:

https://appleid.apple.com/auth/keys

Запросите их через HTTP и закешируйте на короткое время:
php
function getApplePublicKeys(): array {
$response = file_get_contents(‘https://appleid.apple.com/auth/keys’);
return json_decode($response, true)[‘keys’];
}

**4. Декодирование заголовка токена**
Чтобы выбрать нужный ключ по kid (Key ID), декодируйте заголовок JWT без проверки подписи:
php
function getTokenHeader(string $token): array {
$parts = explode(‘.’, $token);
return json_decode(base64_decode(str_pad(strtr($parts[0], ‘-_’, ‘+/’), strlen($parts[0]) % 4, ‘=’, STR_PAD_RIGHT)), true);
}

**5. Конвертация JWK в PEM**
Apple возвращает ключи в формате JWK. Их нужно преобразовать в PEM для проверки подписи:
php
use FirebaseJWTJWK;

$keys = getApplePublicKeys();
$jwks = [‘keys’ => $keys];
$parsedKeys = JWK::parseKeySet($jwks);

Библиотека firebase/php-jwt поддерживает это из коробки начиная с версии 6.x.

**6. Верификация id_token**
php
use FirebaseJWTJWT;
use FirebaseJWTJWK;

function verifyAppleToken(string $idToken, string $clientId): object {
$keysData = json_decode(file_get_contents(‘https://appleid.apple.com/auth/keys’), true);
$publicKeys = JWK::parseKeySet($keysData);

$decoded = JWT::decode($idToken, $publicKeys);

// Проверка издателя и аудитории
if ($decoded->iss !== ‘https://appleid.apple.com’) {
throw new Exception(‘Invalid issuer’);
}
if ($decoded->aud !== $clientId) {
throw new Exception(‘Invalid audience’);
}
if ($decoded->exp < time()) {
throw new Exception('Token expired');
}

return $decoded;
}

**7. Извлечение данных пользователя**
После успешной верификации в объекте $decoded доступны:
— `sub` — уникальный идентификатор пользователя Apple (используйте как user_id)
— `email` — email (может отсутствовать при повторных входах)
— `email_verified` — подтверждён ли email

**8. Важные нюансы**
— Email Apple возвращает только при первом входе пользователя. При повторных — только sub.
— Кешируйте публичные ключи Apple (например, на 1 час), чтобы не делать лишние запросы.
— clientId для веб-приложений — это Services ID из Apple Developer Console, для iOS — Bundle ID.
— Используйте HTTPS и защищайте endpoint от перебора.

Такой подход обеспечивает безопасную серверную верификацию без обращения к дополнительным API Apple.


Задайте вопрос нейросети

Не нашли ответ? Спросите ИИ — он подготовит развёрнутую статью.