Hi everyone,
I'm working on an app that stores multiple secrets in the Keychain, each protected with .userPresence.
My goal is to authenticate the user once via FaceID/TouchID and then read multiple Keychain items without triggering subsequent prompts.
I am reusing the same LAContext instance for these operations, and I have set:
context.touchIDAuthenticationAllowableReuseDuration = LATouchIDAuthenticationMaximumAllowableReuseDuration
However, I'm observing that every single SecItemCopyMatching call triggers a new FaceID/TouchID prompt, even if they happen within seconds of each other using the exact same context.
Here is a simplified flow of what I'm doing:
Create a LAContext.
Set touchIDAuthenticationAllowableReuseDuration to max.
Perform a query (SecItemCopyMatching) for Item A, passing [kSecUseAuthenticationContext: context].
Result: System prompts for FaceID. Success.
Immediately perform a query (SecItemCopyMatching) for Item B, passing the same [kSecUseAuthenticationContext: context].
Result: System prompts for FaceID again.
My question is:
Does the .userPresence access control flag inherently force a new user interaction for every Keychain access, regardless of the LAContext reuse duration? Is allowableReuseDuration only applicable for LAContext.evaluatePolicy calls and not for SecItem queries?
If so, is there a recommended pattern for "unlocking" a group of Keychain items with a single biometric prompt?
Environment: iOS 17+, Swift.
Thanks!
Prioritize user privacy and data security in your app. Discuss best practices for data handling, user consent, and security measures to protect user information.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
Hello,
we are using DeviceCheck – App Attest in a production iOS app. The integration has been live for some time and works correctly for most users, but a small subset of users encounter non-deterministic failures that we are unable to reproduce internally.
Environment
iOS 14+
Real devices only (no simulator)
App Attest capability enabled
Correct App ID, Team ID and App Attest entitlement
Production environment
Relevant code
let service = DCAppAttestService.shared
service.generateKey { keyId, error in
// key generation
}
service.attestKey(keyId, clientDataHash: hash) { attestation, error in
// ERROR: com.apple.devicecheck.error 3 / 4
}
service.generateAssertion(keyId, clientDataHash: clientDataHash) { assertion, error in
// ERROR: com.apple.devicecheck.error 3 / 4
}
For some users we intermittently receive:
com.apple.devicecheck.error error 3
com.apple.devicecheck.error error 4
Characteristics:
appears random
affects only some users/devices
sometimes resolves after time or reinstall
not reproducible on our test devices
NSError contains no additional diagnostic info
Some questions:
What is the official meaning of App Attest errors 3 and 4?
Are these errors related to key state, device conditions, throttling, or transient App Attest service issues?
Is there any recommended way to debug or gain more insight when this happens in production?
Any guidance would be greatly appreciated, as this impacts real users and is difficult to diagnose.
Thank you.
Hi, we were recently approved for the com.apple.developer.web-browser.public-key-credential entitlement and have added it to our app. It initially worked as expected for a couple of days, but then it stopped working. We're now seeing the same error as before adding the entitlement:
Told not to present authorization sheet: Error Domain=com.apple.AuthenticationServicesCore.AuthorizationError Code=1 "(null)"
ASAuthorizationController credential request failed with error: Error Domain=com.apple.AuthenticationServices.AuthorizationError Code=1004 "(null)"
Do you have any insights into what might be causing this issue?
Thank you!
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
I want to add the "Sign In with Apple" feature to my iPadOS application. I've already done the following:
Include com.apple.developer.applesignin in mobileprovision
Include com.apple.developer.applesignin in entitlements
However, I'm getting the following errors:
`Authorization failed: Error Domain=AKAuthenticationError Code=-7026 "(null)" UserInfo={AKClientBundleID=xxxx}
LaunchServices: store (null) or url (null) was nil: Error Domain=NSOSStatusErrorDomain Code=-54 "process may not map database" UserInfo={_LSLine=72, _LSFunction=_LSServer_GetServerStoreForConnectionWithCompletionHandler, _LSFile=LSDReadService.mm, NSDebugDescription=process may not map database}
Attempt to map database failed: permission was denied. This attempt will not be retried.
Failed to initialize client context with error Error Domain=NSOSStatusErrorDomain Code=-54 "process may not map database" UserInfo={_LSLine=72, _LSFunction=_LSServer_GetServerStoreForConnectionWithCompletionHandler, _LSFile=LSDReadService.mm, NSDebugDescription=process may not map database}
Failed to get application extension record: Error Domain=NSOSStatusErrorDomain Code=-54 "(null)"
ASAuthorizationController credential request failed with error: Error Domain=com.apple.AuthenticationServices.AuthorizationError Code=1000 "(null)"
`
What is this problem? How can I solve it?
Hoping someone can help, thank you!
Hello,
I recently installed an iOS app called SpyBuster by MacPaw.
This app shows as list all my installed apps.
How is this possible ?
As a developer, I know this is prohibited by Apple - third party app to scan application workspace.
From watching the video on App Attest the answer would appear to be no, but the video is a few years old so in hope, I thought I would post this question anyway.
There's several scenarios where I would like a notification service extension to be able to use App Attest in communications with the back end(for example to send a receipt to the backend acknowledging receipt of the push, fetching an image from a url in the push payload, a few others).
Any change App Attest can be used in by a notification service extension?
In iOS 18, i use CNContactPickerViewController to access to Contacts (i know it is one-time access).
After first pick up one contact, the Setting > Apps > my app > Contacts shows Private Access without any option to close it.
Is there any way to close it and undisplay it ?
I tried to uninstall and reinstall my app, but it didn't work.
Hi, I’ve added attestation to my app, and everything worked as expected during setup. However, after deployment, I noticed some unknownSystemFailure entries in the production logs on New Relic. Could you help me understand what typically causes this error? The documentation suggests issues such as failing to generate a token. What scenarios could lead to that?
Hi, is it legal to use open APIs to get the users's country country code using the Ip address in the app? I mean I want to know the user country for the game leaderboards data, and there are sites say this is free and open. So, I have two questions, first, is this making the user calling open api to get its country code concept legal? second question, what if these sites suddenly decided that it is not legal to use their apis for commercial use, and i miss that announcement; will you remove my app from the store? or what action will you take exactly?
Recently I am trying to implement apple oauth in expo web version, I created the service id and other related info, i have issue
@PostMapping("/callback")
public ResponseEntity handleAppleCallback(@RequestParam Map<String, String> body) {
String code = body.get("code");
String idToken = body.get("id_token");
if (code == null) {
return ResponseEntity.badRequest().build();
}
// Redirect to your Expo Web app with the code in query
String frontendUrl = "https://mobile-dot-dev-epicportal.uc.r.appspot.com/apple-callback?code=" + code;
return ResponseEntity.status(HttpStatus.FOUND)
.header("Location", frontendUrl)
.build();
}
when i pass the code recived from apple to this route i am getting invalid_grant
i am not sure what is wrong here
I have implemented "Sign in With Apple" in my app , but problem is when user logged in initially or first time and email I can retrieve , name and email but after that when i tried to re login it is giving null value for name and email, why it is happening and what should be done here?
Topic:
Privacy & Security
SubTopic:
Sign in with Apple
I'm implementing Apple Sign-In in my Next.js application with a NestJS backend. After the user authenticates with Apple, instead of redirecting to my configured callback URL, the browser makes a POST request to a mysterious endpoint /appleauth/auth/federate that doesn't exist in my codebase, resulting in a 404 error.
Tech Stack
Frontend: Next.js 16.0.10, React 19.2.0
Backend: NestJS with Passport (using @arendajaelu/nestjs-passport-apple)
Frontend URL: https://myapp.example.com
Backend URL: https://api.example.com
Apple Developer Configuration
Service ID: (configured correctly in Apple Developer Console)
Return URL (only one configured):
https://api.example.com/api/v1/auth/apple/callback
Domains verified in Apple Developer Console:
myapp.example.com
api.example.com
example.com
Backend Configuration
NestJS Controller (auth.controller.ts):
typescript
@Public()
@Get('apple')
@UseGuards(AuthGuard('apple'))
async appleAuth() {
// Initiates Apple OAuth flow
}
@Public()
@Post('apple/callback') // Changed from @Get to @Post for form_post
@UseGuards(AuthGuard('apple'))
async appleAuthCallback(@Req() req: any, @Res() res: any) {
const result = await this.authService.socialLogin(req.user, ipAddress, userAgent);
// Returns HTML with tokens that uses postMessage to send to opener window
}
Environment Variables:
typescript
APPLE_CLIENT_ID=<service_id>
APPLE_TEAM_ID=<team_id>
APPLE_KEY_ID=<key_id>
APPLE_PRIVATE_KEY_PATH=./certs/AuthKey_XXX.p8
APPLE_CALLBACK_URL=https://api.example.com/api/v1/auth/apple/callback
FRONTEND_URL=https://myapp.example.com
The passport-apple strategy uses response_mode: 'form_post', so Apple POSTs the authorization response to the callback URL.
Frontend Implementation
Next.js API Route (/src/app/api/auth/apple/route.js):
javascript
export async function GET(request) {
const backendUrl = new URL(`${API_URL}/auth/apple`);
const response = await fetch(backendUrl.toString(), {
method: "GET",
headers: {
"Content-Type": "application/json",
},
});
const responseText = await response.text();
return new NextResponse(responseText, {
status: response.status,
headers: { "Content-Type": contentType || "text/html" },
});
}
Frontend Auth Handler:
javascript
export const handleAppleLogin = (router, setApiError) => {
const frontendUrl = window?.location?.origin;
// Opens popup to /api/auth/apple
window.open(
`${frontendUrl}/api/auth/apple`,
"appleLogin",
"width=500,height=600"
);
};
The Problem
Expected Flow:
User clicks "Login with Apple"
Frontend opens popup → https://myapp.example.com/api/auth/apple
Frontend proxies to → https://api.example.com/api/v1/auth/apple
Backend redirects to Apple's authentication page
User authenticates with Apple ID
Apple POSTs back to → https://api.example.com/api/v1/auth/apple/callback
Backend processes and returns success HTML
Actual Behavior:
After step 5 (user authentication with Apple), instead of Apple redirecting to my callback URL, the browser makes this unexpected request:
POST https://myapp.example.com/appleauth/auth/federate?isRememberMeEnabled=false
Status: 404 Not Found
Request Payload:
json
{
"accountName": "user@example.com",
"rememberMe": false
}
Network Tab Analysis
From Chrome DevTools, the call stack shows:
send @ app.js:234
ajax @ app.js:234
(anonymous) @ app.js:10
Ee.isFederated @ app.js:666
_callAuthFederate @ app.js:666
The Ee.isFederated and _callAuthFederate functions appear to be minified library code, but I cannot identify which library.
What I've Verified
✅ The /appleauth/auth/federate endpoint does not exist anywhere in my codebase:
bash
grep -r "appleauth" src/ # No results
grep -r "federate" src/ # No results
✅ Apple Developer Console shows only ONE Return URL configured (verified multiple times)
✅ Changed callback route from @Get to @Post to handle form_post response mode
✅ Rebuilt frontend completely multiple times:
bash
rm -rf .next
npm run build
✅ Tested in:
Incognito/Private browsing mode
Different browsers (Chrome, Firefox, Safari)
Different devices
After clearing all cache and cookies
✅ No service workers registered in the application
✅ No external <script> tags or CDN libraries loaded
✅ package.json contains no AWS Amplify, Auth0, Cognito, or similar federated auth libraries
✅ Checked layout.js and all root-level files - no external scripts
Additional Context
Google Sign-In works perfectly fine using the same approach
The mysterious endpoint uses a different path structure (/appleauth/ vs /api/auth/)
The call appears to originate from client-side JavaScript (based on the call stack)
The app.js file with the mysterious functions is the built Next.js bundle
Questions
Where could this /appleauth/auth/federate endpoint be coming from?
Why is the browser making this POST request instead of following Apple's redirect to my configured callback URL?
Could this be related to the response_mode: 'form_post' in the Apple Passport strategy?
Is there something in the Apple Developer Primary App ID configuration that could trigger this behavior?
Could this be a Next.js build artifact or some hidden dependency?
The mysterious call stack references (Ee.isFederated, _callAuthFederate) suggest some library is intercepting the Apple authentication flow, but I cannot identify what library or where it's being loaded from. The minified function names suggest federated authentication, but I have no such libraries in my dependencies.
Has anyone encountered similar issues with Apple Sign-In where an unexpected endpoint is being called?
Topic:
Privacy & Security
SubTopic:
Sign in with Apple
Tags:
Sign in with Apple REST API
Sign in with Apple
Hi everyone,
I’m developing a multiplayer iOS game that uses Multipeer Connectivity for local peer-to-peer networking. I’d like to display user-assigned device names in the UI to help players identify each other during the connection process. In iOS 16 and later, accessing UIDevice.current.name requires the User-Assigned Device Name Entitlement.
The documentation states that the entitlement is granted for functionality involving “interaction between multiple devices that the same user operates”. My game is strictly multiplayer, with devices owned by different users, not a single user managing multiple devices.
I have a few questions regarding this:
Does the requirement for “devices operated by the same user” definitively exclude multiplayer scenarios where devices belong to different players? Can a Multipeer Connectivity-based game qualify for the entitlement in this case?
If the entitlement is not applicable, is prompting users to enter custom names the recommended approach for identifying devices in a multiplayer UI?
Has anyone successfully obtained this entitlement for a similar multiplayer use case with Multipeer Connectivity?
Thanks in advance.
Hi everyone,
We just completed an App Store Connect app transfer between two developer teams and ran into what seems like an inconsistency with TN3159 (Migrating Sign in with Apple users for an app transfer).
According to the technote, both the source and destination teams should be able to call /auth/usermigrationinfo for 60 days after the transfer, even if the migration wasn’t run beforehand. However, right after the transfer completed, the source team (Team A) started receiving:
{"error":"invalid_client"}
on all /auth/usermigrationinfo requests, even though /auth/token with scope=user.migration still works fine.
What we verified before transfer:
Team A’s Sign in with Apple key (ES256) was linked to the app and Services ID.
OAuth flow for com.org.appname.web returned valid tokens, and the decoded ID token showed aud=com.org.appname.web with a valid private relay email, confirming the key was trusted.
What happens after transfer:
The key now shows “Enabled Services: —” and the App/Services IDs are no longer selectable in the Developer portal.
/auth/usermigrationinfo immediately returns invalid_client for Team A, even within the same day of the transfer.
This effectively makes Team A unable to generate transfer_sub values, blocking the migration flow TN3159 describes.
Questions:
Is Team A supposed to retain authorization to call /auth/usermigrationinfo for 60 days post-transfer?
If yes, is there any known workaround to re-authorize the key or temporarily re-bind it to the transferred identifiers?
If not, does this mean transfer_sub must be generated before transfer acceptance, contrary to how TN3159 reads?
Would really appreciate any confirmation or guidance from Apple or anyone who’s gone through this recently.
Thanks,
Topic:
Privacy & Security
SubTopic:
Sign in with Apple
Tags:
Sign in with Apple REST API
Sign in with Apple
We recently deployed Attestation on our application, and for a majority of the 40,000 users it works well. We have about six customers who are failing attestation. In digging through debug logs, we're seeing this error "iOS assertion verification failed. Unauthorized access attempted." We're assuming that the UUID is blocked somehow on Apple side but we're stumped as to why. We had a customer come in and we could look at the phone, and best we can tell it's just a generic phone with no jailbroken or any malicious apps. How can we determine if the UUID is blocked?
We are using Apple's PSSO to federate device login to out own IdP. We have developed our own extension app and deployed it using MDM. Things works fine but there are 2 issues that we are trying to get to the root cause -
On some devices after restarting we see an error message on the logic screen saying "The registration for this device is invalid and must be repaired"
And other error message is "SmartCard configuration is invalid for this account"
For the 1st we have figured out that this happens when the registration doesn't happen fully and the key is not tied to the user so when the disk needs to be decrypted at the FileVault screen the issue is raised.
For the "SmartCard configuration is invalid for this account" issue also one aspect is invalid registration but there has been other instances as well where the devices were registered completely but then also the the above error was raised. We verified the registration being completed by checking if the SmartCard is visible in the System Report containing the key.
Has anyone seen the above issues and any possible resolution around it?
We are using ASWebAuthenticationSession with apps on IoS to achieve SSO between apps. The IdP for authentication (OIDC) is an on-premise and trusted enterprise IdP based on one of the leading products in the market. Our problem is that the user is prompted for every login (and logouts) with a consent dialogue box:
“AppName” wants to use “internal domain-name” to Sign In
This allows the app and website to share information about you.
Cancel Continue”
I have read in various places that Apple has a concept of “Trusted domains” where you can put an “Apple certified” static web-page on the IdP. This page needs to contain specific metadata that iOS can verify. Once a user logs in successfully a few times, and if the IdP is verified as trusted, subsequent logins would not prompt the consent screen.
Question: I struggle to find Apple documentation on how to go about a process that ends with this “Apple certified web-page” on our IdP”. Anyone who has experience with this process, or who can point me in some direction to find related documentation?
I managed to lose my password in a mixup with my password manager. It has taken me a few hours to work out how to reset it. Following the forgotten password link on the sign in page only takes you to a point where you are asked to reset the password on your iCloud user id. If they are one and the same that's ok. Mine aren't.
I eventually found the answer:
in the settings app choose developer
2 scroll to the end and choose the sandbox apple account
3. choose this and reset
When developing and testing using my phone I got prompted for allowing app tracking. I later uploaded a build to TestFlight, deleted the old testing app and installed the TestFlight build. I am now stuck in an infinite loop of not getting prompted for allowing app tracking for the app. When entering the app settings the toggle for tracking never appears which leaves me not able to enter the app's content. My guess is that the prompt can only be shown once for the app bundle, but there has to be a way for me to get prompted again without changing the app bundle id. Help is appreciated since this app is scheduled to be published in a week.