Supported APIs for macOS screen-lock state and graphical-session binding

We are qualifying a local macOS control service on Apple Silicon, macOS 26.5.2 (25F84). Browser control sessions must be revoked on graphical screen lock; unlock must not restore old sessions. Background project execution and durable pending decisions continue independently.

We built a correctly signed user-context helper using its own data protection Keychain access group and a nonsecret WhenUnlockedThisDeviceOnly item. Every call uses a fresh noninteractive LAContext and requests actual item data. In one user-confirmed stock screen lock/unlock test, reads returned errSecInteractionNotAllowed while locked and expected data after unlock. This is one observation, not a general screen-state contract.

The installed EndpointSecurity SDK explicitly states that es_graphical_session_id_t is not an audit session ID. CoreGraphics public caller-session properties expose UID, on-console and login-done, but no documented lock-state/current ES graphical-session identifier.

  1. What supported API maps a caller Aqua user-context process or NSXPCConnection audit session to the relevant ES graphical_session_id? If none exists, what supported binding should a trusted user-context helper use for current graphical lock authority, including Fast User Switching and Screen Sharing contexts?
  2. Does a fresh successful macOS DP WhenUnlockedThisDeviceOnly data read imply that this graphical session is unlocked? How does the documented SSH path that unlocks the login Keychain and DP Keychain interact with a still-locked graphical session or another context of the same UID?
  3. Is there a supported coherent current-lock snapshot/subscription mechanism for initial startup or observer restart? What completeness, ordering and maximum latency contracts apply to userspace-produced ES LoginWindow lock events? Does any supported fence detect a final delayed/lost lock or a lock+unlock between two protected reads?
  4. Does any supported API bind the unlocked condition to a subsequent application control decision, such as an application-owned SQLite COMMIT? A receiver-side monotonic freshness check can reject late replies during coordinator stalls, but its final check and COMMIT remain separate operations. We seek a supported contract or OS-enforced mechanism for this boundary.

We can conservatively revoke all broker control sessions on any trusted graphical lock instead of guessing an ASID→graphical-ID mapping, but this still leaves bootstrap/current-state and event completeness open. We have not assumed private CGSession keys, audit authentication flags, a helper heartbeat, or a queue-tail fence prove screen-unlocked state.

Primary references: TN3137, SecItem: Pitfalls and Best Practices, ES graphical session ID, CG session dictionary, XPC audit session.

Answered by DTS Engineer in 909226022

Thanks for that explanation. It was very clear.

Given those requirements I’m inclined to recommend the NSApplicationProtectedDataDidBecomeAvailable notification. It’s not directly tied to screen lock state but rather to the state of the keybag [1] that controls access to protected data on the file system and in the keychain. If, for example, you store a credential in the keychain [2] such that it’s accessible when unlocked, this tells you whether it’s accessible or not. That seems appropriate for your goal here.

Keep in mind that this state is only accessible from within GUI login session (it’s an AppKit API and AppKit is only supported within a GUI login session). So you’ll need some sort of process running within the session to pick this up, for example, a launchd agent. However, I don’t think that’ll be a problem in your case because you’re already doing stuff, like dealing with web browsers, that requires you to be running within the GUI login session.

Also note that if you search the ’net you’ll find a bunch of info about screen lock and unlock notifications. AFAICT these are all implementation details rather than API.

Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] See Apple Platform Security for a definition of that term.

[2] Specifically, the data protection keychain.

To offer assistance here I need to know more about the context of this question. Let’s start with this:

We are qualifying a local macOS control service on Apple silicon

What does this actually mean? Can you describe more about what your product does at the user level?

Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Its local macOS application for managing long-running AI software-development projects. A user describes a product goal, reviews the proposed plan, and lets the application coordinate implementation over days or weeks. When a decision or approval is needed, the user handles it through a browser-based interface on the Mac.

That interface can issue project-control commands and approve actions that the AI must not take on its own. If the Mac’s graphical session locks, we need to revoke the browser’s authority to issue those commands. Unlocking must require a new control session; it must not reactivate the old one. Project work that was already authorized may continue in the background, and pending decisions remain saved.

We are trying to determine which supported macOS mechanisms can enforce that boundary, including when the user switches accounts or connects through Screen Sharing.

Accepted Answer

Thanks for that explanation. It was very clear.

Given those requirements I’m inclined to recommend the NSApplicationProtectedDataDidBecomeAvailable notification. It’s not directly tied to screen lock state but rather to the state of the keybag [1] that controls access to protected data on the file system and in the keychain. If, for example, you store a credential in the keychain [2] such that it’s accessible when unlocked, this tells you whether it’s accessible or not. That seems appropriate for your goal here.

Keep in mind that this state is only accessible from within GUI login session (it’s an AppKit API and AppKit is only supported within a GUI login session). So you’ll need some sort of process running within the session to pick this up, for example, a launchd agent. However, I don’t think that’ll be a problem in your case because you’re already doing stuff, like dealing with web browsers, that requires you to be running within the GUI login session.

Also note that if you search the ’net you’ll find a bunch of info about screen lock and unlock notifications. AFAICT these are all implementation details rather than API.

Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] See Apple Platform Security for a definition of that term.

[2] Specifically, the data protection keychain.

Thank you, Quinn. I want to make sure we don't mistake protected-data availability for a guarantee about graphical screen lock. Our security requirement is to revoke browser control on every lock of the relevant GUI session, including Fast User Switching and Screen Sharing. Does macOS guarantee that protected data becomes unavailable in each of those cases? If it can remain available while that graphical session is locked, would you recommend a different supported boundary for this requirement? We can use the AppKit notifications to revoke promptly, but would also need to establish the state when the agent starts and avoid authorizing a command solely from a previously received notification.

Does macOS guarantee that protected data becomes unavailable in each of those cases?

No.

Well, it’s something that I expect to happen but I doubt you’ll find any guarantees as to the exact circumstances as to when it does [1].

Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] If such things did exist they’d be in Apple Platform Security. I took a quick look and couldn’t spot anything.