תארו לעצמכם: משתמש iOS מצפה להיכנס לאתר דרך Apple ID, אבל יש לכם רק Google ואימייל. הוא עוזב למתחרה. נתקלנו בזה פעמים רבות. שילוב Sign in with Apple אינו רק עמידה בהנחיות—זו דרך לשמר משתמשי מכשירי Apple. לפי נתוני הפרויקטים שלנו, שיעור ההמרה של התחברות דרך Apple ID בקרב משתמשי iOS גבוה ב-25-30% מאשר דרך Google או אימייל—זה פי 1.3 טוב יותר לשימור משתמשים. עם זאת, היישום מסתיר מלכודות רבות: אימייל ממסלול מנותב (relay) לא מגיע, שם המשתמש אובד בכניסה חוזרת, client_secret פג תוקף כל 6 חודשים. יש לנו ניסיון של 10+ שנים בפיתוח אתרים ומעל 50 פרויקטי הרשאות מוצלחים. אנו מבטיחים פעולה תקינה גם עם אימייל ממסלול מנותב ונתונים מוסתרים, חוסכים עד $2000 בעלויות פיתוח ו-20 שעות על ניפוי שגיאות טיפוסיות. השקעה: מ-$500 לשילוב מלא.
אתגרים טיפוסיים בשילוב Apple ID
ל-Apple ID יש מספר מאפיינים שהופכים את היישום ללא טריוויאלי:
- המשתמש יכול להסתיר את האימייל האמיתי שלו—Apple מנפיקה כתובת ממסלול מנותב כמו
[email protected]. -
id_tokenמוחזר רק בהרשאה הראשונה יחד עם שם המשתמש. - כניסות עוקבות לא מחזירות את השם—יש לשמור אותו בכניסה הראשונה.
- אין refresh token במובן הרגיל של OAuth2.
ההבדלים הללו דורשים גישה מיוחדת: אנו מטפלים בקפדנות בכל תרחיש כדי להבטיח שהמשתמש לא יאבד גישה. לפי התיעוד של Apple, כתובות ממסלול מנותב עשויות לשנות פורמט—אנו מתחשבים בכך ביישום שלנו.
רישום אפליקציה ב-Apple Developer
- Certificates, Identifiers & Profiles → Identifiers → צרו App ID עם Sign In with Apple מופעל.
- צרו Services ID (רכיב אינטרנט)—ציינו את הדומיין ואת כתובת ה-Redirect URL.
- צרו Key עם Sign In with Apple מופעל—הורידו את קובץ
.p8(שמרו במקום בטוח; ניתן להוריד רק פעם אחת). - רשמו את Team ID, Client ID (= Services ID), Key ID.
יצירת client_secret
Apple אינה משתמשת בסוד סטטי. client_secret הוא JWT חתום עם מפתח .p8 פרטי. אנו יוצרים אותו באמצעות ספריית lcobucci/jwt:
use Lcobucci\JWT\Configuration;
use Lcobucci\JWT\Signer\Ecdsa\Sha256;
use Lcobucci\JWT\Signer\Key\InMemory;
function generateAppleClientSecret(): string
{
$config = Configuration::forAsymmetricSigner(
new Sha256(),
InMemory::file(storage_path('keys/apple_auth.p8')),
InMemory::empty()
);
return $config->builder()
->issuedBy(config('services.apple.team_id')) // iss: Team ID
->permittedFor('https://appleid.apple.com') // aud
->relatedTo(config('services.apple.client_id')) // sub: Services ID
->issuedAt(new \DateTimeImmutable())
->expiresAt(new \DateTimeImmutable('+6 months'))
->withHeader('kid', config('services.apple.key_id'))
->getToken($config->signer(), $config->signingKey())
->toString();
}הטוקן תקף עד 6 חודשים. אנו מחדשים אותו מוקדם דרך cron—אנו הופכים זאת לאוטומטי כדי לשמור על פעילות רציפה של השילוב.
במה שונה Apple OAuth מ-Google OAuth?
השוואת פרוטוקולים
1. Редирект пользователя: GET https://appleid.apple.com/auth/authorize
?client_id=com.example.web
&redirect_uri=https://example.com/auth/apple/callback
&response_type=code id_token
&response_mode=form_post
&scope=name email
&state=<random_string>
&nonce=<random_nonce>
2. Apple делает POST на redirect_uri с:
- code
- id_token
- state
- user (JSON с именем — только при первом входе!)חשוב: use Lcobucci\JWT\Configuration; use Lcobucci\JWT\Signer\Ecdsa\Sha256; use Lcobucci\JWT\Signer\Key\InMemory; function generateAppleClientSecret(): string { $config = Configuration::forAsymmetricSigner( new Sha256(), InMemory::file(storage_path('keys/apple_auth.p8')), InMemory::empty() ); return $config->builder() ->issuedBy(config('services.apple.team_id')) // iss: Team ID ->permittedFor('https://appleid.apple.com') // aud ->relatedTo(config('services.apple.client_id')) // sub: Services ID ->issuedAt(new \DateTimeImmutable()) ->expiresAt(new \DateTimeImmutable('+6 months')) ->withHeader('kid', config('services.apple.key_id')) ->getToken($config->signer(), $config->signingKey()) ->toString(); } —Apple שולחת POST, לא GET. כתובת ה-redirect חייבת לקבל POST.
| מאפיין | Apple ID | Google OAuth |
|---|---|---|
| Client secret | JWT עם מפתח .p8 (עד 6 חודשים) | client_secret סטטי |
| העברת נתונים | טופס POST עם code ו-id_token | הפניה GET עם code |
| שם משתמש | רק בכניסה הראשונה | בכל כניסה |
| אימייל ממסלול מנותב | אופציונלי | אין |
| Refresh token | אין (נדרשת כניסה חוזרת) | זמין (אם נדרש) |
Apple OAuth מורכב פי 2-3 ליישום אך נותן גישה לקהל מכשירי iOS. הניסיון מראה ששיעור ההמרה של התחברות דרך Apple ID גבוה ב-25-30% בקרב משתמשי Apple.
טיפול ב-Callback ואימות id_token
public function handleCallback(Request $request): RedirectResponse {
// Верификация state
abort_unless($request->state === session('apple_state'), 422);
// Декодирование id_token (без верификации подписи пока)
$idToken = $this->decodeIdToken($request->id_token);
// user приходит только при первом входе
$appleUser = $request->has('user') ? json_decode($request->user, true) : null;
$user = User::updateOrCreate(
['apple_id' => $idToken['sub']],
[
'email' => $idToken['email'] ?? null,
'email_verified_at' => $idToken['email_verified'] ? now() : null,
// Имя сохраняем только если пришло (первый вход)
'name' => $appleUser ? trim(($appleUser['name']['firstName'] ?? '') . ' ' . ($appleUser['name']['lastName'] ?? '')) : null,
]
);
// Обновляем имя только если оно не было установлено ранее
if ($appleUser && !$user->name) {
$user->update(['name' => ...]);
}
Auth::login($user);
return redirect()->intended('/dashboard');
} אימות id_token
Apple מפרסמת מפתחות ציבוריים ב-1. Редирект пользователя: GET https://appleid.apple.com/auth/authorize ?client_id=com.example.web &redirect_uri=https://example.com/auth/apple/callback &response_type=code id_token &response_mode=form_post &scope=name email &state=<random_string> &nonce=<random_nonce> 2. Apple делает POST на redirect_uri с: - code - id_token - state - user (JSON с именем — только при первом входе!) . אימות באמצעות JWT:
// composer require firebase/php-jwt
use Firebase\JWT\JWT;
use Firebase\JWT\JWK;
$keys = Cache::remember('apple_public_keys', 3600, function () {
return Http::get('https://appleid.apple.com/auth/keys')->json();
});
$payload = JWT::decode($idToken, JWK::parseKeySet($keys));
// Проверить: iss = appleid.apple.com, aud = client_id, exp, nonce עבודה עם אימייל ממסלול מנותב
אם המשתמש מסתיר את האימייל שלו, Apple מנפיקה כתובת ממסלול מנותב response_mode=form_post. אימיילים לכתובת זו מגיעים רק אם הדומיין רשום ב-Apple Developer Console → More → Configure Sign in with Apple for Email Communication. אנו עוזרים להגדיר תהליך זה כך שהודעות יישלחו.
בפרויקט אחד, אימייל ממסלול מנותב נכשל כי הדומיין לא היה רשום—השגיאה עלתה ללקוח בחלק מההזמנות. זיהינו במהירות את הסיבה והגדרנו את המיפוי, והחזרנו את משלוח האימיילים.
מה כלול בעבודה
- רישום האפליקציה ב-Apple Developer (App ID, Services ID, Key)
- יצירת client_secret JWT עם חידוש אוטומטי דרך cron
- יישום OAuth callback עם אימות id_token ו-state
- טיפול באימייל ממסלול מנותב ושם מוסתר (שמירה בכניסה הראשונה)
- שילוב עם Laravel Socialite Apple או יישום מותאם אישית
- תיעוד לתחזוקה והעברת אישורים
- אחריות על הקוד וייעוץ חינם בתוך חודש לאחר המסירה
לוחות זמנים
| שלב | זמן |
|---|---|
| רישום ב-Apple Developer | 0.5 ימים |
| מחולל client_secret + cron | יום אחד |
| OAuth callback + אימות id_token | 1.5 ימים |
| שמירת אימייל ממסלול מנותב, טיפול בשם | 0.5 ימים |
| בדיקות + אימות במכשירים אמיתיים | יום אחד |
סה"כ: 4–5 ימי עבודה.
כדי לקבל שילוב Apple ID מוכן, צרו קשר—נעריך את הפרויקט שלכם ונציע פתרון אופטימלי. לפי הנתונים שלנו, 40% ממשתמשי iOS נוטשים את ההתחברות אם Apple ID אינו זמין. הזמינו את השילוב היום וחסכו לעצמכם שעות של ניפוי שגיאות טיפוסיות.







