From 6187dc1907ffb55e7d5aecac1ba0a6d69b464323 Mon Sep 17 00:00:00 2001 From: Daniel Arantes Loverde Date: Fri, 31 Jul 2026 14:09:41 -0300 Subject: [PATCH] [app-attest-env] Clear stale App Attest key on local DCError, not just server 403 Root cause of the permanent stuck-at-challenge symptom: a stale appAttestKeyId in Keychain (Secure Enclave key invalidated by an app reinstall or signing change) makes generateAssertion fail every time with DCError code 2 (invalidInput). Only NetworkError 403 was clearing the stored key, so this local rejection was never recovered from - every guest-authed call kept retrying the same broken key forever. Catch DCError here too and fall through to fresh attestation. --- Sources/PediFoods/Services/GuestSessionService.swift | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Sources/PediFoods/Services/GuestSessionService.swift b/Sources/PediFoods/Services/GuestSessionService.swift index 9206983..411bace 100644 --- a/Sources/PediFoods/Services/GuestSessionService.swift +++ b/Sources/PediFoods/Services/GuestSessionService.swift @@ -113,6 +113,15 @@ actor GuestSessionService { // other error (network blip, timeout, decode issue) must // NOT wipe a perfectly valid registered key. store.appAttestKeyId = nil + } catch let error as DCError { + // DeviceCheck itself rejects the key locally (e.g. the app + // was reinstalled and the Secure Enclave key backing this + // keyId no longer exists) - distinct from the server + // rejecting it, but equally unrecoverable without a fresh + // key. Without this, generateAssertion fails the same way + // forever since appAttestKeyId is never cleared. + print("[GuestSessionService] existing key rejected locally, re-attesting with a fresh key: \(error)") + store.appAttestKeyId = nil } }