Prioritize user privacy and data security in your app. Discuss best practices for data handling, user consent, and security measures to protect user information.

All subtopics
Posts under Privacy & Security topic

Post

Replies

Boosts

Views

Activity

How to programmatically stop passkey in my app
I am using Auth0 as a login manager for our app. The way Auth0 handles login is that their SDK will create a web view where the login is actually handled. Once the login is finished the session will end and the app will gain control. We are not set up for passkeys in their system and can't set up quickly to do that. Unfortunately with the new iOS "passkey is the primary login" way iOS is set up now, users are asked to use passkey when it's not supported on the backend. I don't have direct control of the login screens. Is there any way, at the app level, to tell the app to not use passkeys so that it quits showing up as an option for the users? I can't find any documentation on doing this. How can I stop passkey in my app entirely?
0
0
303
Feb ’25
identifier for vender (IDFV) in Enterprise Build
Hi, I have a question about UIDevice identifierForVendor. I am distributing 3 apps using an enterprise account. All apps use the same developer account and certificates. The bundle IDs of the apps are as follows: com.abc.inhouse.mail com.abc.searchent com.abc.noteent In the Enterprise builds, apps 1 and 2 share the same identifierForVendor (IDFV). However, app 3 has a different IDFV value. According to Apple documentation, the IDFV is determined based on the bundle ID when distributing through Enterprise. Why does app 3 have a different IDFV? Are there any other factors besides the bundle ID that affect the IDFV in Enterprise builds? Please help me figure this out. Thank you for your time!
0
0
233
Jan ’25
Password AutoFill does not pick up saved password in developer mode
Without developer mode, I was able to get Password AutoFill to work in my SwiftUI app with my local Vapor server using ngrok and adding the Associated Domains capability with the value webcredentials:....ngrok-free.app and the respective apple-app-site-association file on my local server in /.well-known/. (works on device, but not in the simulator). However, if I use the developer mode (webcredentials:....ngrok-free.app?mode=developer) it only works halfway when running from Xcode: I get asked to save the password, but the saved passwords are not picked up, when I try to login again. Neither on device, nor in the simulator. If I remove the ?mode=developer it seems to work as expected. Is this by design, or am I missing something? var body: some View { ... Section(header: Text("Email")) { TextField("Email", text: $viewModel.credentials.username) .textContentType(.username) .autocapitalization(.none) .keyboardType(.emailAddress) } Section(header: Text("Passwort")) { SecureField("Passwort", text: $viewModel.credentials.password) .textContentType(.password) } ... }
0
0
175
May ’25
Passkey Registration Fails with “UnexpectedRPIDHash” on iOS — Domain & Associated Domains Confirmed Correct
I’m implementing Passkey registration on iOS using ASAuthorizationPlatformPublicKeyCredentialProvider. On the server side, I’m using a WebAuthn library that throws the error UnexpectedRPIDHash: Unexpected RP ID hash during verifyRegistrationResponse(). Domain: pebblepath.link (publicly routable, valid SSL certificate, no warnings in Safari) Associated Domains in Xcode**: webcredentials:pebblepath.link AASA file: { "applinks": { "apps": [] }, "webcredentials": { "apps": [ "H33XH8JMV6.com.reactivex.pebblepath" ] } } Xcode Configuration: Team ID: H33XH8JMV6 Bundle ID: com.reactivex.pebblepath Associated Domains: webcredentials:pebblepath.link Logs: iOS clientDataJSON shows "origin": "https://pebblepath.link". Server logs confirm expectedOrigin = "https://pebblepath.link" and expectedRPID = "pebblepath.link". Despite this, the server library still errors out: finishRegistration error: UnexpectedRPIDHash. I’ve verified that: The domain has a valid CA-signed SSL cert (no Safari warnings). The AASA file is reachable at https://pebblepath.link/.well-known/apple-app-site-association. The app’s entitlements match H33XH8JMV6.com.reactivex.pebblepath. I’ve removed old passkeys from Settings → Passwords on the device and retried fresh. I’m testing on a real device with iOS 16+; I am using a Development provisioning profile, but that shouldn’t cause an RP ID mismatch as long as the domain is valid. Every log indicates that the domain and origin match exactly, but the WebAuthn library still throws UnexpectedRPIDHash, implying iOS is embedding a different (or unrecognized) RP ID hash in the credential. Has anyone else encountered this with iOS passkeys and a valid domain/AASA setup? Is there an extra step needed to ensure iOS recognizes the domain for passkey registration? Any guidance or insights would be greatly appreciated!
1
0
560
Jan ’25
Sign in with Apple Sync Issues Across Teams
We have 2 developers: Developer A created a Bundle ID and configured Sign in with Apple, but didn't create a corresponding App. This Bundle ID is only used for login on our official website. Developer B created a Bundle ID, configured Sign in with Apple, and has a corresponding App. The issue we're encountering is that because these two Bundle IDs are under different teams, when using the same Apple ID to log into these two applications, different accounts are generated. (We've tested that when creating Service IDs under the same team, logging in with Bundle IDs under the same team generates the same account.) Since Developer A's Bundle ID doesn't have a created app, it cannot be transferred to Developer B. Therefore, we'd like to know if there's any way to make the accounts generated from logging in with the same Apple ID be identical across these two teams?
0
0
381
Feb ’25
com.apple.developer.web-browser.public-key-credential still leads to com.apple.AuthenticationServices.AuthorizationError Code=1004
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!
2
0
173
May ’25
Sign in with Apple Keychain savedEmail Stored Incorrectly
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") } }
0
0
280
Mar ’25
Backup Eligibility and Backup State has set to true for support hybrid transport with legacy authenticators
My application is supporting hybrid transport on FIDO2 webAuthn specs to create credential and assertion. And it support legacy passkeys which only mean to save to 1 device and not eligible to backup. However In my case, if i set the Backup Eligibility and Backup State flag to false, it fails on the completion of the registrationRequest to save the passkey credential within credential extension, the status is false instead of true. self.extension.completeRegistrationRequest(using: passkeyRegistrationCredential) The attestation and assertion flow only works when both flags set to true. Can advice why its must have to set both to true in this case?
0
0
112
Sep ’25
About Configure Sign in with Apple for Email Communication
In response to inquiries from users, we have confirmed the following phenomenon. If you select "Private email address" in the flow of new user registration with Apple ID, you will not receive the verification code email when performing two-factor authentication. ■User impact If you use your Apple ID to link an external account without making your email address public, you will not receive the authentication code during two-factor authentication and will not be able to proceed. The date and time of the impact is currently unknown. ◎Impact 1: New registration If you select "Private email address" in the flow of registering a new user with Apple ID, the verification code will not be received during two-factor authentication and registration will not be completed. ◎Impact 2: Login of existing account When two-factor authentication is required for an existing account registered with Apple ID set to "Private email address," the verification code is not received and the user cannot log in. →If you have not registered a login method other than Apple ID for the relevant account, there is no other way to log in. ■About workarounds ・I thought that I could avoid this issue by canceling the private setting of my Apple ID, but I was unable to do so. →There is currently no workaround found for existing users who are experiencing this issue. ・However, the scope of influence is limited. ■Cause investigation status Premise: For an Apple ID whose email address is not made public, the two-factor authentication authentication code email follows the following route. ①CDC/GIGYA miraiz-persol.jp (SendGrid) Apple's email server (relay server to hide the user's real email address) User mailbox →Since '1' are working, the problem seems to have occurred after the connection from ② or ③. (At this stage, we cannot determine who is at fault: the user, MIRAIZ, or Apple. We are currently investigating.) ◎Hypothesis ・Is there something wrong with Apple's mail server? ・Is it not delivered because the user's mailbox is full? ■Questions, research, and responses we would like to receive Please check the following two points and reply. 1st point As shown in the attached image, there seems to be no problem with the SPF settings. Is it possible to check to see if any errors have occurred with Apple's mail server? 2nd point Are there any cases where you still can't receive emails even if you deactivate your Apple ID? I would like to know if there are any patterns in which emails are not being delivered in terms of past inquiries or overall specifications
1
0
384
Mar ’25
Handling ITMS-91061: Missing privacy manifest
An ITMS-91061: Missing privacy manifest rejection email looks as follows: ITMS-91061: Missing privacy manifest- Your app includes "<path/to/SDK>", which includes , an SDK that was identified in the documentation as a privacy-impacting third-party SDK. Starting February 12, 2025, if a new app includes a privacy-impacting SDK, or an app update adds a new privacy-impacting SDK, the SDK must include a privacy manifest file. Please contact the provider of the SDK that includes this file to get an updated SDK version with a privacy manifest. For more details about this policy, including a list of SDKs that are required to include signatures and manifests, visit: https://developer.apple.com/support/third-party-SDK-requirements. Glossary ITMS-91061: Missing privacy manifest: An email that includes the name and path of privacy-impacting SDK(s) with no privacy manifest files in your app bundle. For more information, see https://developer.apple.com/support/third-party-SDK-requirements. : The specified privacy-impacting SDK that doesn't include a privacy manifest file. If you are the developer of the rejected app, gather the name of the SDK from the email you received from Apple, then contact the SDK's provider for an updated version that includes a valid privacy manifest. After receiving an updated version of the SDK, verify the SDK includes a valid privacy manifest file at the expected location. For more information, see Adding a privacy manifest to your app or third-party SDK. If your app includes a privacy manifest file, make sure the file only describes the privacy practices of your app. Do not add the privacy practices of the SDK to your app's privacy manifest. If the email lists multiple SDKs, repeat the above process for all of them. If you are the developer of an SDK listed in the email, publish an updated version of your SDK that includes a privacy manifest file with valid keys and values. Every privacy-impacting SDK must contain a privacy manifest file that only describes its privacy practices. To learn how to add a valid privacy manifest to your SDK, see the Additional resources section below. Additional resources Privacy manifest files Describing data use in privacy manifests Describing use of required reason API Adding a privacy manifest to your app or third-party SDK TN3182: Adding privacy tracking keys to your privacy manifest TN3183: Adding required reason API entries to your privacy manifest TN3184: Adding data collection details to your privacy manifest TN3181: Debugging an invalid privacy manifest
0
0
5.8k
Mar ’25
How to distinguish the "no credential found" scenario from ASAuthorizationError
Hello everyone, I'm developing a FIDO2 service using the AuthenticationServices framework. I've run into an issue when a user manually deletes a passkey from their password manager. When this happens, the ASAuthorizationError I get doesn't clearly indicate that the passkey is missing. The error code is 1001, and the localizedDescription is "The operation couldn't be completed. No credentials available for login." The userInfo also contains "NSLocalizedFailureReason": "No credentials available for login." My concern is that these localized strings will change depending on the user's device language, making it unreliable for me to programmatically check for a "no credentials" scenario. Is there a more precise way to determine that the user has no passkey, without relying on localized string values? Thank you for your help.
0
0
325
Sep ’25
appleid.apple.com response servers IPs
Developers of our e-shop are preparing to enable Apple Sign In for account login. Apple ID verification is conducted via the domain appleid.apple.com, and the responses should be coming back from the following two Apple IP addresses: IPv4 Address: 17.32.194.6 IPv4 Address: 17.32.194.37 Question is whether these addresses are correct and if they remain unchanged over time. Alternatively, it is existing an official list of IP addresses that may be used for Apple Sign In verification response? This is necessary to ensure precise network communication settings and protection by F5 security solution. Thanks a lot for answers.
0
0
150
Mar ’25
App Groups: macOS vs iOS: Working Towards Harmony
I regularly see folks confused by the difference in behaviour of app groups between macOS and iOS. There have been substantial changes in this space recently. While much of this is now covered in the official docs (r. 92322409), I’ve updated this post to go into all the gory details. If you have questions or comments, start a new thread with the details. Put it in the App & System Services > Core OS topic area and tag it with Code Signing and Entitlements. Oh, and if your question is about app group containers, also include Files and Storage. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" App Groups: macOS vs iOS: Working Towards Harmony There are two styles of app group ID: iOS-style app group IDs start with group., for example, group.eskimo1.test. macOS-style app group IDs start with your Team ID, for example, SKMME9E2Y8.eskimo1.test. This difference has been the source of numerous weird problems over the years. Starting in Feb 2025, iOS-style app group IDs are fully supported on macOS for all product types [1]. If you’re writing new code that uses app groups, use an iOS-style app group ID. If you have existing code that uses a macOS-style app group ID, consider how you might transition to the iOS style. IMPORTANT The Feb 2025 changes aren’t tied to an OS release but rather to a Developer website update. For more on this, see Feb 2025 Changes, below. [1] If your product is a standalone executable, like a daemon or agent, wrap it in an app-like structure, as explained in Signing a daemon with a restricted entitlement. iOS-Style App Group IDs An iOS-style app group ID has the following features: It starts with the group. prefix, for example, group.eskimo1.test. You allocate it on the Developer website. This assigns the app group ID to your team. You then claim access to it by listing it in the App Groups entitlement (com.apple.security.application-groups) entitlement. That claim must be authorised by a provisioning profile [1]. The Developer website will only let you include your team’s app group IDs in your profile. For more background on provisioning profiles, see TN3125 Inside Code Signing: Provisioning Profiles. iOS-style app group IDs originated on iOS with iOS 3.0. They’ve always been supported on iOS’s child platforms (iPadOS, tvOS, visionOS, and watchOS). On the Mac: They’ve been supported by Mac Catalyst since that technology was introduced. Likewise for iOS Apps on Mac. Starting in Feb 2025, they’re supported for other Mac products. [1] Strictly speaking macOS does not require that, but if your claim is not authorised by a profile then you might run into other problems. See Entitlements-Validated Flag, below. macOS-Style App Group IDs A macOS-style app group ID has the following features: It should start with your Team ID [1], for example, SKMME9E2Y8.eskimo1.test. It can’t be explicitly allocated on the Developer website. Code that isn’t sandboxed doesn’t need to claim the app group ID in the App Groups entitlement. [2] To use an app group, claim the app group ID in the App Groups entitlement. The App Groups entitlement is not restricted on macOS, meaning that this claim doesn’t need to be authorised by a provisioning profile [3]. However, if you claim an app group ID that’s not authorised in some way, you might run into problems. More on that later in this post. If you submit an app to the Mac App Store, the submission process checks that your app group IDs make sense, that is, they either start with your Team ID (macOS style) or are assigned to your team (iOS style). [1] This is “should” because, historically, macOS has not actually required it. However, that’s now changing, with things like app group container protection. [2] This was true prior to macOS 15. It may still technically be true in macOS 15 and later, but the most important thing, access to the app group container, requires the entitlement because of app group container protection. [3] Technically it’s a validation-required entitlement, something that we’ll come back to in the Entitlements-Validated Flag section. Feb 2025 Changes On 21 Feb 2025 we rolled out a change to the Developer website that completes the support for iOS-style app group IDs on the Mac. Specifically, it’s now possible to create a Mac provisioning profile that authorises the use of an iOS-style app group ID. Note This change doesn’t affect Mac Catalyst or iOS Apps on Mac, which have always been able to use iOS-style app group IDs on the Mac. Prior to this change it was possible to use an iOS-style app group ID on the Mac but that might result in some weird behaviour. Later sections of this post describe some of those problems. Of course, that information is now only of historical interest because, if you’re using an iOS-style app group, you can and should authorise that use with a provisioning profile. We also started seeding Xcode 16.3, which has since been release. This is aware of the Developer website change, and its Signing & Capabilities editor actively encourages you to use iOS-style app groups IDs in all products. Note This Xcode behaviour is the only option for iOS and its child platforms. With Xcode 16.3, it’s now the default for macOS as well. If you have existing project, enable this behaviour using the Register App Groups build setting. Finally, we updated a number of app group documentation pages, including App Groups entitlement and Configuring app groups. Crossing the Streams In some circumstances you might need to have a single app that accesses both an iOS- and a macOS-style app group. For example: You have a macOS app. You want to migrate to an iOS-style app group ID, perhaps because you want to share an app group container with a Mac Catalyst app. But you also need to access existing content in a container identified by a macOS-style app group ID. Historically this caused problems (FB16664827) but, as of Jun 2025, this is fully supported (r. 148552377). When the Developer website generates a Mac provisioning profile for an App ID with the App Groups capability, it automatically adds TEAM_ID.* to the list of app group IDs authorised by that profile (where TEAM_ID is your Team ID). This allows the app to claim access to every iOS-style app group ID associated with the App ID and any macOS-style app group IDs for that team. This helps in two circumstances: It avoids any Mac App Store Connect submission problems, because App Store Connect can see that the app’s profile authorises its use of all the it app group IDs it claims access to. Outside of App Store — for example, when you directly distribute an app using Developer ID signing — you no longer have to rely on macOS granting implicit access to macOS-style app group IDs. Rather, such access is explicitly authorised by your profile. That ensures that your entitlements remain validated, as discussed in the Entitlements-Validated Flag, below. A Historical Interlude These different styles of app group IDs have historical roots: On iOS, third-party apps have always used provisioning profiles, and thus the App Groups entitlement is restricted just like any other entitlement. On macOS, support for app groups was introduced before macOS had general support for provisioning profiles [1], and thus the App Groups entitlement is unrestricted. The unrestricted nature of this entitlement poses two problems. The first is accidental collisions. How do you prevent folks from accidentally using an app group ID that’s in use by some other developer? On iOS this is easy: The Developer website assigns each app group ID to a specific team, which guarantees uniqueness. macOS achieved a similar result by using the Team ID as a prefix. The second problem is malicious reuse. How do you prevent a Mac app from accessing the app group containers of some other team? Again, this isn’t an issue on iOS because the App Groups entitlement is restricted. On macOS the solution was for the Mac App Store to prevent you from publishing an app that used an app group ID that’s used by another team. However, this only works for Mac App Store apps. Directly distributed apps were free to access app group containers of any other app. That was considered acceptable back when the Mac App Store was first introduced. That’s no longer the case, which is why macOS 15 introduced app group container protection. See App Group Container Protection, below. [1] I’m specifically talking about provisioning profiles for directly distributed apps, that is, apps using Developer ID signing. Entitlements-Validated Flag The fact that the App Groups entitlement is unrestricted on macOS is, when you think about it, a little odd. The purpose of entitlements is to gate access to functionality. If an entitlement isn’t restricted, it’s not much of a gate! For most unrestricted entitlements that’s not a problem. Specifically, for both the App Sandbox and Hardened Runtime entitlements, those are things you opt in to, so macOS is happy to accept the entitlement at face value. After all, if you want to cheat you can just not opt in [1]. However, this isn’t the case for the App Groups entitlement, which actually gates access to functionality. Dealing with this requires macOS to walk a fine line between security and compatibility. Part of that solution is the entitlements-validated flag. When a process runs an executable, macOS checks its entitlements. There are two categories: Restricted entitlements must be authorised by a provisioning profile. If your process runs an executable that claims a restricted entitlement that’s not authorised by a profile, the system traps. Unrestricted entitlements don’t have to be authorised by a provisioning profile; they can be used by any code at any time. However, the App Groups entitlement is a special type of unrestricted entitlement called a validation-required entitlement. If a process runs an executable that claims a validation-required entitlement and that claim is not authorised by a profile, the system allows the process to continue running but clears its entitlements-validated flag. Some subsystems gate functionality on the entitlements-validated flag. For example, the data protection keychain uses entitlements as part of its access control model, but refuses to honour those entitlements if the entitlement-validated flag has been cleared. Note If you’re curious about this flag, use the procinfo subcommand of launchctl to view it. For example: % sudo launchctl procinfo `pgrep Test20230126` … code signing info = valid … entitlements validated … If the flag has been cleared, this line will be missing from the code signing info section. Historically this was a serious problem because it prevented you from creating an app that uses both app groups and the data protection keychain [2] (r. 104859788). Fortunately that’s no longer an issue because the Developer website now lets you include the App Groups entitlement in macOS provisioning profiles. [1] From the perspective of macOS checking entitlements at runtime. There are other checks: The App Sandbox is mandatory for Mac App Store apps, but that’s checked when you upload the app to App Store Connect. Directly distributed apps must be notarised to pass Gatekeeper, and the notary service requires that all executables enable the hardened runtime. [2] See TN3137 On Mac keychain APIs and implementations for more about the data protection keychain. App Groups and the Keychain The differences described above explain a historical oddity associated with keychain access. The Sharing access to keychain items among a collection of apps article says: Application groups When you collect related apps into an application group using the App Groups entitlement, they share access to a group container, and gain the ability to message each other in certain ways. You can use app group names as keychain access group names, without adding them to the Keychain Access Groups entitlement. On iOS this makes a lot of sense: The App Groups entitlement is a restricted entitlement on iOS. The Developer website assigns each iOS-style app group ID to a specific team, which guarantees uniqueness. The required group. prefix means that these keychain access groups can’t collide with other keychain access groups, which all start with an App ID prefix (there’s also Apple-only keychain access groups that start with other prefixes, like apple). However, this didn’t work on macOS [1] because the App Groups entitlement is unrestricted there. However, with the Feb 2025 changes it should now be possible to use an iOS-style app group ID as a keychain access group on macOS. Note I say “should” because I’ve not actually tried it (-: Keep in mind that standard keychain access groups are protected the same way on all platforms, using the restricted Keychain Access Groups entitlement (keychain-access-groups). [1] Except for Mac Catalyst apps and iOS Apps on Mac. Not Entirely Unsatisfied When you launch a Mac app that uses app groups you might see this log entry: type: error time: 10:41:35.858009+0000 process: taskgated-helper subsystem: com.apple.ManagedClient category: ProvisioningProfiles message: com.example.apple-samplecode.Test92322409: Unsatisfied entitlements: com.apple.security.application-groups Note The exact format of that log entry, and the circumstances under which it’s generated, varies by platform. On macOS 13.0.1 I was able to generate it by running a sandboxed app that claims a macOS-style app group ID in the App Groups entitlement and also claims some other restricted entitlement. This looks kinda worrying and can be the source of problems. It means that the App Groups entitlement claims an entitlement that’s not authorised by a provisioning profile. On iOS this would trap, but on macOS the system allows the process to continue running. It does, however, clear the entitlements-validate flag. See Entitlements-Validated Flag for an in-depth discussion of this. The easiest way to avoid this problem is to authorise your app group ID claims with a provisioning profile. If there’s some reason you can’t do that, watch out for potential problems with: The data protection keychain — See the discussion of that in the Entitlements-Validated Flag and App Groups and the Keychain sections, both above. App group container protection — See App Group Container Protection, below. App Group Container Protection macOS 15 introduced app group container protection. To access an app group container without user intervention: Claim access to the app group by listing its ID in the App Groups entitlement. Locate the container by calling the containerURL(forSecurityApplicationGroupIdentifier:) method. Ensure that at least one of the following criteria are met: Your app is deployed via the Mac App Store (A). Or via TestFlight when running on macOS 15.1 or later (B). Or the app group ID starts with your app’s Team ID (C). Or your app’s claim to the app group is authorised by a provisioning profile embedded in the app (D) [1]. If your app doesn’t follow these rules, the system prompts the user to approve its access to the container. If granted, that consent applies only for the duration of that app instance. For more on this, see: The System Integrity Protection section of the macOS Sequoia 15 Release Notes The System Integrity Protection section of the macOS Sequoia 15.1 Release Notes WWDC 2024 Session 10123 What’s new in privacy, starting at 12:23 The above criteria mean that you rarely run into the app group authorisation prompt. If you encounter a case where that happens, feel free to start a thread here on DevForums. See the top of this post for info on the topic and tags to use. Note Prior to the Feb 2025 change, things generally worked out fine when you app was deployed but you might’ve run into problems during development. That’s no longer the case. [1] This is what allows Mac Catalyst and iOS Apps on Mac to work. Revision History 2025-08-12 Added a reference to the Register App Groups build setting. 2025-07-28 Updated the Crossing the Streams section for the Jun 2025 change. Made other minor editorial changes. 2025-04-16 Rewrote the document now that iOS-style app group IDs are fully supported on the Mac. Changed the title from App Groups: macOS vs iOS: Fight! to App Groups: macOS vs iOS: Working Towards Harmony 2025-02-25 Fixed the Xcode version number mentioned in yesterday’s update. 2025-02-24 Added a quick update about the iOS-style app group IDs on macOS issue. 2024-11-05 Further clarified app group container protection. Reworked some other sections to account for this new reality. 2024-10-29 Clarified the points in App Group Container Protection. 2024-10-23 Fleshed out the discussion of app group container protection on macOS 15. 2024-09-04 Added information about app group container protection on macOS 15. 2023-01-31 Renamed the Not Entirely Unsatisfactory section to Not Entirely Unsatisfied. Updated it to describe the real impact of that log message. 2022-12-12 First posted.
0
0
5.2k
Aug ’25
Conditional Display of Passkey Provider in macOS \ iOS
Hello, I've developed a macOS app with an AutoFill Credential Provider extension that functions as a passkey provider. In the registration flow, I want my app to appear as a passkey provider only when specific conditions are met. Is there a way to inspect the request from the web before the passkey provider selection list is displayed to the user, determine whether my app can handle it, and then use that result to instruct the OS on whether to include my app in the passkey provider selection list? Alternatively, is there a way to predefine conditions that must be met before my app is offered as a passkey provider in the selection list? Thanks!
3
0
487
Feb ’25
App Sandbox Resources
General: Forums subtopic: Privacy & Security > General Forums tag: App Sandbox App Sandbox documentation App Sandbox Design Guide documentation — This is no longer available from Apple. There’s still some info in there that isn’t covered by the current docs but, with the latest updates, it’s pretty minimal (r. 110052019). Still, if you’re curious, you can consult an old copy [1]. App Sandbox Temporary Exception Entitlements archived documentation — To better understand the role of temporary exception entitlements, see this post. Embedding a command-line tool in a sandboxed app documentation Discovering and diagnosing App Sandbox violations (replaces the Viewing Sandbox Violation Reports forums post) Resolving App Sandbox Inheritance Problems forums post The Case for Sandboxing a Directly Distributed App forums post Implementing Script Attachment in a Sandboxed App forums post Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" [1] For example, this one archived by the Wayback Machine.
0
0
2.7k
Jul ’25
Local Authentication & localized reason string
In a project I was using Local Authentication to authenticate a user. When I got a request to support smartcard/PIV token authentication (which Local Authentication does not support), I had to switch to Authorization Services, which works pretty. There's only one issue I have. Local Authentication's evaluatePolicy:localizedReason:reply: requires a reason in the form "&lt;appname&gt;" is trying to &lt;localized reason&gt;. The app is currently translated into 41 languages and I would like to use the localized strings for the AuthorizationEnvironment of Authorization Services as well. The problem is that Local Authentication prefixes the localized string with something like "&lt;appname&gt;" is trying to and Authorization Services does not do this. Is there a way to get this prefix from somewhere so I can manually add it to the (partially) localized string? Any help would be highly appreciated. Thank you, Marc
7
0
836
Feb ’25