Apple 2019’da Sign in with Apple’ı tanıttı ve App Store Guideline 4.8 ile şu kuralı koydu: üçüncü taraf login (Google, Facebook, vb) sunan app Sign in with Apple’ı da sunmalı. Bu zorunluluğu atlayan app review’da reddedilir.
12 uygulamamda farklı auth setup’ları yaptım. Sign in with Apple başta basit görünen, detaylarda karmaşık bir entegrasyon. Bu yazıda pratik notlar.
Neden Apple bu kadar dayatıyor
Sign in with Apple’ın Apple için iki stratejik kazancı:
– Privacy: email relay, ad tracking yok, üçüncü parti veri minimize
– Ekosistem lock-in: iCloud ile derinleşen kullanıcı bağı
Developer için kazancı: onboarding friction düşük (tek dokunuş), kullanıcı email address’i verebilir veya relay kullanabilir, biometric auth zaten cihazda.
Kullanıcı için: privacy-first login seçeneği.
Zorunluluğa rağmen iyi bir tool olduğunu söyleyebilirim. 12 app’te ekledim, pişman değilim.
ASAuthorization framework
iOS 13+ için AuthenticationServices framework’ü kullanılıyor.
Minimal implementation:
import AuthenticationServices
class SignInViewController: UIViewController, ASAuthorizationControllerDelegate {
func signInWithApple() {
let request = ASAuthorizationAppleIDProvider().createRequest()
request.requestedScopes = [.fullName, .email]
let controller = ASAuthorizationController(authorizationRequests: [request])
controller.delegate = self
controller.presentationContextProvider = self
controller.performRequests()
}
func authorizationController(
controller: ASAuthorizationController,
didCompleteWithAuthorization authorization: ASAuthorization
) {
if let credential = authorization.credential as? ASAuthorizationAppleIDCredential {
let userId = credential.user
let identityToken = credential.identityToken
let authCode = credential.authorizationCode
// backend'e gönder
}
}
}Apple Sign In UI butonu ASAuthorizationAppleIDButton class’ı ile native geliyor, custom tasarlama gerekli değil (ve Apple özelleştirmeye izin vermiyor – uyarı geliyor review’da).
Backend doğrulama: identity token
Client’tan gelen identity token JWT. Apple’ın public key’leri ile signature verify edilmeli. Client’ın gönderdiği userId’ye güvenmeyin, identity token’dan çıkarın.
Backend’de adımlar:
- Apple public keys endpoint’inden fetch:
https://appleid.apple.com/auth/keys - JWT header’daki
kid‘e göre doğru public key seç - Signature verify et
- Claims kontrol et:
iss == "https://appleid.apple.com",aud == your_bundle_id,exp > now subclaim’i user’ın unique ID’si,emailvarsa email relay veya real
PHP örneği:
use Firebase\JWT\JWT;
use Firebase\JWT\JWK;
$jwks = json_decode(file_get_contents('https://appleid.apple.com/auth/keys'), true);
$keys = JWK::parseKeySet($jwks);
$decoded = JWT::decode($identityToken, $keys);Library kullanın, manuel JWT parse etmeyin.
Email relay: gizli email
Kullanıcı “email’imi paylaşma” seçeneğini seçebiliyor. Bu durumda Apple xxxx@privaterelay.appleid.com formatında unique bir relay email veriyor.
Email bu adrese gidiyor, Apple kullanıcının gerçek email’ine iletiyor. Kullanıcı istediği zaman relay’i kesebiliyor, o noktadan sonra email’leriniz gidmiyor.
Dikkat:
– Relay email’e pazarlama email göndermek Apple Terms ihlali (developer portal’dan kaldırılabilirsiniz)
– Email iletilebilir olmalı (SPF, DKIM doğru ayarlı, güvenilir gönderen)
– DB’de email’i aynen kaydedin, “real email” ayrı bir field olarak ayırın
User identifier persistence
Apple sub claim’i sabittir, app reinstall olsa bile aynı kullanıcı için aynı ID. Ama:
– Farklı bundle ID’lere farklı sub verir (app’inizin iki varyantı varsa kullanıcı iki hesap)
– Team ID değişirse sub’lar sıfırlanır
Bu nedenle user matching sadece sub ile yapmayın. Email, phone, ya da diğer unique key’lerle fallback bulundurun.
Revocation webhook: zorunluluk
2022’den sonra Apple developer’ların kullanıcı Sign in with Apple’ı iptal ettiğinde bildirim alması için webhook endpoint kurmasını zorunlu kıldı. Uymayan app’ler yeni submission’da reddediliyor.
Setup:
1. Apple Developer Portal’da Sign in with Apple webhook URL’i kaydet
2. Endpoint POST request alıyor, events field’ı JWT
3. JWT’yi parse et, event type kontrol et
4. Event’e göre aksiyon: kullanıcıyı sil, disable et, gracefully kapat
Event types:
– consent-revoked: kullanıcı Sign in with Apple’ı kaldırdı
– account-delete: kullanıcı Apple ID’yi sildi
– email-disabled: email relay kapatıldı
– email-enabled: email relay tekrar açıldı
Bu event’leri handle etmek GDPR compliance için de önemli. “Right to be forgotten” Apple tarafından iletildiği anda honor edilmeli.
Nonce kullanımı
Replay attack’a karşı nonce zorunlu. Client sign-in request’ini yaparken random nonce üretir, SHA256 hash’ini request’e koyar, orijinal nonce’u Firebase veya backend validation’a gönderir.
let nonce = randomNonceString()
let request = ASAuthorizationAppleIDProvider().createRequest()
request.nonce = sha256(nonce)Backend JWT’deki nonce claim’i ile client’ın gönderdiği orijinal nonce’u match ediyor. Farklıysa replay attack.
SwiftUI implementation
SwiftUI’da daha şık:
import AuthenticationServices
SignInWithAppleButton { request in
request.requestedScopes = [.fullName, .email]
request.nonce = sha256(currentNonce)
} onCompletion: { result in
switch result {
case .success(let authorization):
handleAuthorization(authorization)
case .failure(let error):
handleError(error)
}
}
.signInWithAppleButtonStyle(.black)
.frame(height: 50)iOS 14+.
Error handling
Kullanıcı sign-in akışını iptal edebilir, network hatası olabilir. Yaygın errors:
ASAuthorizationError.canceled: kullanıcı iptal etti, sessizce geçASAuthorizationError.failed: teknik hata, generic mesajASAuthorizationError.invalidResponse: token bozuk, retry önerilebilirASAuthorizationError.notHandled: system errorASAuthorizationError.unknown: beklenmeyen
Her durumda kullanıcıya ne yapacağını söyleyin. “Apple login başarısız” yerine “İnternet bağlantınızı kontrol edin ve tekrar deneyin” daha iyi.
Test disiplini
Simulator’da Sign in with Apple çalışır ama sınırlı. Real device test şart.
Test Apple ID’lerinin ayrı tutulması önemli: test user’ların real email address’i de kullanabilirler, ama test account hesaplarını Apple Sandbox’ta yönetin, production user pool’una karışmasın.
Performans etkisi
Sign in with Apple’ı kullanan app’lerde onboarding completion rate’im:
– Email/password: %35
– Google Sign-In: %62
– Sign in with Apple: %74
Friction gerçekten düşük. Face ID tap ile sign-in, hiç form doldurma yok. Kullanıcıların %40+’ı Sign in with Apple’ı tercih ediyor, email/password hiç tercih etmiyor.
Tavsiye
Sign in with Apple’ı “zorunlu olduğu için” değil, “iyi çalıştığı için” eklemek fark yaratıyor. Default login seçeneği olarak promote edin, revocation webhook’u ilk implementation’da ekleyin, email relay’e saygılı olun.
Bu 3 madde hem Apple ile iyi durmanızı hem de kullanıcı memnuniyetini sağlıyor.