Section 10/161 menit
10. Error Handling dan Edge Cases
10. Error Handling dan Edge Cases
Semua Error Code ASAuthorization
swift
extension AuthenticationCoordinator: ASAuthorizationControllerDelegate {
func authorizationController(
controller: ASAuthorizationController,
didCompleteWithError error: Error
) {
let authError = error as? ASAuthorizationError
switch authError?.code {
case .canceled:
// User tap Cancel atau tekan Home — NORMAL, jangan tampilkan error ke user
handleUserCanceled()
case .failed:
// Biometrik gagal (fingerprint tidak cocok) atau passkey tidak valid
handleAuthenticationFailed(error)
case .invalidResponse:
// Response dari authenticator tidak valid — mungkin bug atau security issue
handleInvalidResponse(error)
case .notHandled:
// Request tidak bisa ditangani — biasanya karena tidak ada passkey yang match
handleNoPasskeyFound()
case .unknown:
// Catch-all untuk error tak terduga
handleUnknownError(error)
case .notInteractive:
// Request memerlukan interaksi user tapi kondisi tidak memungkinkan
// (misal: AutoFill request tapi tidak ada field aktif)
handleNonInteractiveError()
case .matchedExcludedCredential:
// Credential yang dicoba register sudah ada di excluded credentials
// (Duplikasi registration dicegah)
handleDuplicateCredential()
default:
handleUnknownError(error)
}
}
private func handleNoPasskeyFound() {
// Fallback ke password login
showPasswordLoginForm()
}
private func handleUserCanceled() {
// Resume conditional AutoFill jika ada
Task { await beginConditionalSignIn() }
}
}
Edge Cases yang Sering Diabaikan
swift
// 1. Device baru setelah factory reset — iCloud Keychain belum sync
func handleFirstLaunchAfterReset() async {
// Passkey mungkin belum tersedia — iCloud sync butuh waktu
// Tampilkan loading state atau opsi login alternatif
if !isPasskeyAvailable() {
showAlternativeLoginOptions()
// Monitor iCloud sync state dengan CKContainer
}
}
// 2. Account upgrade: user register passkey sementara masih login via password
func upgradeToPasskey() async throws {
// 1. Verifikasi sesi password masih valid
guard sessionManager.isAuthenticated else { throw UpgradeError.notAuthenticated }
// 2. Register passkey baru
let registration = try await registerNewPasskey()
// 3. Kirim ke server — server simpan passkey DAN tetap simpan password hash
try await server.addPasskeyToAccount(registration, keepPassword: true)
// 4. Tandai di UserDefaults bahwa upgrade sudah dilakukan
UserDefaults.standard.set(true, forKey: "passkeyUpgraded")
}
// 3. Multiple devices — passkey di device lain
// iCloud Keychain sync otomatis, tapi ada delay
// Berikan UI yang jelas bahwa passkey bisa digunakan dari semua device iCloud
// 4. Excluded credentials — mencegah duplikasi
func registerNewPasskey(excludingExisting: [Data]) async throws {
let request = provider.createCredentialRegistrationRequest(...)
// Cegah register ulang credential yang sudah ada
request.excludedCredentials = excludingExisting.map {
ASAuthorizationPlatformPublicKeyCredentialDescriptor(credentialID: $0)
}
// Jika user coba register credential yang sudah ada → .matchedExcludedCredential error
}