Using personal physical iPhone for simulations. Can't get Keychain to read or store AppleID name/email. I want to avoid hard reseting physical phone.
Logs confirm Keychain is working, but userIdentifier and savedEmail are not being stored correctly.
π Initializing UserManager...
β
Saved testKeychain to Keychain: Test Value
β
Retrieved testKeychain from Keychain: Test Value
π Keychain Test - Retrieved Value: Test Value
β οΈ Keychain Retrieve Warning: No stored value found for userIdentifier
β οΈ Keychain Retrieve Warning: No stored value found for savedEmail
π Debug - Retrieved from Keychain: userIdentifier=nil, savedEmail=nil
β οΈ No stored userIdentifier in Keychain. User needs to sign in.
π¦ Converting User to CKRecord: Unknown, No Email
β
User saved locally: Unknown, No Email
β
User saved to CloudKit: Unknown, No Email
Below UserManager.swift if someone can help troubleshoot. Or step by step tutorial to configure a project and build a User Login & User Account creation for Apple Only app.
import Foundation
import CloudKit
import AuthenticationServices
import SwiftData
@MainActor
class UserManager: ObservableObject {
@Published var user: User?
@Published var isLoggedIn = false
@Published var errorMessage: String?
private let database = CKContainer.default().publicCloudDatabase
init() {
print("π Initializing UserManager...")
// π Keychain Debug Test
let testKey = "testKeychain"
KeychainHelper.shared.save("Test Value", forKey: testKey)
let retrievedValue = KeychainHelper.shared.retrieve(forKey: testKey)
print("π Keychain Test - Retrieved Value: \(retrievedValue ?? "nil")")
fetchUser() // Continue normal initialization
}
// β
Sign in & Save User
func handleSignIn(_ authResults: ASAuthorization) {
guard let appleIDCredential = authResults.credential as? ASAuthorizationAppleIDCredential else {
errorMessage = "Error retrieving Apple credentials"
print("β ASAuthorization Error: Invalid credentials received")
return
}
let userIdentifier = appleIDCredential.user
let fullName = appleIDCredential.fullName?.givenName ?? retrieveSavedName()
var email = appleIDCredential.email ?? retrieveSavedEmail()
print("π Apple Sign-In Data: userIdentifier=\(userIdentifier), fullName=\(fullName), email=\(email)")
// π If Apple doesn't return an email, check if it exists in Keychain
if appleIDCredential.email == nil {
print("β οΈ Apple Sign-In didn't return an email. Retrieving saved email from Keychain.")
}
// β
Store userIdentifier & email in Keychain
KeychainHelper.shared.save(userIdentifier, forKey: "userIdentifier")
KeychainHelper.shared.save(email, forKey: "savedEmail")
let newUser = User(fullName: fullName, email: email, userIdentifier: userIdentifier)
saveUserToCloudKit(newUser)
}
func saveUserToCloudKit(_ user: User) {
let record = user.toRecord()
Task {
do {
try await database.save(record)
DispatchQueue.main.async {
self.user = user
self.isLoggedIn = true
self.saveUserLocally(user)
print("β
User saved to CloudKit: \(user.fullName), \(user.email)")
}
} catch {
DispatchQueue.main.async {
self.errorMessage = "Error saving user: \(error.localizedDescription)"
print("β CloudKit Save Error: \(error.localizedDescription)")
}
}
}
}
// β
Fetch User from CloudKit
func fetchUser() {
let userIdentifier = KeychainHelper.shared.retrieve(forKey: "userIdentifier")
let savedEmail = KeychainHelper.shared.retrieve(forKey: "savedEmail")
print("π Debug - Retrieved from Keychain: userIdentifier=\(userIdentifier ?? "nil"), savedEmail=\(savedEmail ?? "nil")")
guard let userIdentifier = userIdentifier else {
print("β οΈ No stored userIdentifier in Keychain. User needs to sign in.")
return
}
let predicate = NSPredicate(format: "userIdentifier == %@", userIdentifier)
let query = CKQuery(recordType: "User", predicate: predicate)
Task { [weak self] in
guard let self = self else { return }
do {
let results = try await self.database.records(matching: query, resultsLimit: 1).matchResults
if let (_, result) = results.first {
switch result {
case .success(let record):
DispatchQueue.main.async {
let fetchedUser = User(record: record)
self.user = User(
fullName: fetchedUser.fullName,
email: savedEmail ?? fetchedUser.email,
userIdentifier: userIdentifier
)
self.isLoggedIn = true
self.saveUserLocally(self.user!)
print("β
User loaded from CloudKit: \(fetchedUser.fullName), \(fetchedUser.email)")
}
case .failure(let error):
DispatchQueue.main.async {
print("β Error fetching user from CloudKit: \(error.localizedDescription)")
}
}
}
} catch {
DispatchQueue.main.async {
print("β CloudKit fetch error: \(error.localizedDescription)")
}
}
}
}
// β
Save User Locally
private func saveUserLocally(_ user: User) {
if let encoded = try? JSONEncoder().encode(user) {
UserDefaults.standard.set(encoded, forKey: "savedUser")
UserDefaults.standard.set(user.fullName, forKey: "savedFullName")
UserDefaults.standard.set(user.email, forKey: "savedEmail")
print("β
User saved locally: \(user.fullName), \(user.email)")
} else {
print("β Local Save Error: Failed to encode user data")
}
}
// β
Retrieve Previously Saved Name
private func retrieveSavedName() -> String {
return UserDefaults.standard.string(forKey: "savedFullName") ?? "Unknown"
}
// β
Retrieve Previously Saved Email
private func retrieveSavedEmail() -> String {
return KeychainHelper.shared.retrieve(forKey: "savedEmail") ?? UserDefaults.standard.string(forKey: "savedEmail") ?? "No Email"
}
// β
Sign Out
func signOut() {
isLoggedIn = false
user = nil
UserDefaults.standard.removeObject(forKey: "savedUser")
print("πͺ Signed Out")
}
}
Topic:
Privacy & Security
SubTopic:
General
Tags:
Sign in with Apple
Authentication Services
iCloud Keychain Verification Codes