AutoFill credential provider extension deadlocks on TKSmartCard.beginSession() during a passkey request on iOS 27

We ship a credential provider extension (ASCredentialProviderViewController, ProvidesPasskeys = true) backed by a USB CCID smart card token. It works on iOS 26.6. On iOS 27.0, TKSmartCard.beginSession() inside the extension never returns during a passkey request.

The CryptoTokenKit log shows why. When a passkey request starts, AuthenticationServicesAgent takes an exclusive session on the reader to check whether it is a hardware security key. The check takes about 7 ms and comes back negative — our token has no FIDO applet. The agent then keeps the session for the rest of the request anyway. Our extension asks for the card 0.2 s later and gets queued behind it:

14:24:13.687776  usbsmartcardreaderd          session requested by pid 2116 (1 now queued)
14:24:13.687793  usbsmartcardreaderd          session busy (held by pid 2095); notifying holder
14:24:13.687849  AuthenticationServicesAgent  got request for used session, setting flag to release it ASAP
14:24:34.884294  AuthenticationServicesAgent  got request for used session, setting flag to release it ASAP
14:25:19.851779  AuthenticationServicesAgent  got request for used session, setting flag to release it ASAP
14:26:12.501296  AuthenticationServicesAgent  endSession
14:26:12.502320  usbsmartcardreaderd          session granted to pid 2116

pid 2095 is the agent, pid 2116 is our extension. The system tells the holder three times that someone is waiting; it is released 118.8 s later, when the passkey request itself times out — by which point the card is useless to us.

So it deadlocks: the agent holds the card until the request finishes, and the request cannot finish until we get the card to sign the assertion.

One detail suggests this is not deliberate. The agent takes the session twice in a row and runs the identical check both times. The first one it releases after a second; the second one is the one that sticks. We saw the same pattern on two different days.

We have not found any point in the request where the card is free. Things that do not work: grabbing it as early as viewDidLoad; grabbing it in provideCredentialWithoutUserInteraction before any UI appears; holding it in the containing app and handing it over once the extension starts (the queue is FIFO and the agent is ahead of us); and simply waiting, since the block lasts exactly as long as the request does.

Has anyone else hit this?

Has anyone shipped a smart-card-backed credential provider on iOS 27 and found a way around it? Is there any way to stop the system from claiming an attached reader while a passkey request is in flight — a setting, an Info.plist key, something on the relying party side, anything at all? We would happily take an ugly workaround at this point. And if you hit this and got nowhere either, that is useful to hear too — it would tell us this is not specific to our token.

Questions

  1. Once the check has come back negative, the reader is known not to be a security key. Is there a supported way to make the agent release it at that point, or for an extension to declare that it needs exclusive access?

  2. Can this be turned off from Safari or from the relying party side? For an assertion (navigator.credentials.get): does hints: ["client-device"], or leaving usb out of transports in allowCredentials, stop the agent from claiming the reader? If so, that is a real mitigation for anyone who controls their own relying party. (authenticatorSelection.authenticatorAttachment only exists on registration options, so it is not available here.)

  3. Is TKSmartCard.beginSession() meant to block indefinitely, with no timeout and no cancellation? It bridges beginSessionWithReply:, so Swift concurrency cancellation does not reach it either. Failing with an error after a bounded wait would at least make this diagnosable instead of presenting as a hang.

Filed as FB24171032 with a minimal sample project and full logs.

Hardware, in case it matters: Aktiv Rutoken ECP, USB CCID. Any CCID reader without a FIDO applet should behave the same. iPhone 15 Pro on iOS 27.0 fails; iPhone 17 Pro on iOS 26.6 works, same binary and same token.

AutoFill credential provider extension deadlocks on TKSmartCard.beginSession() during a passkey request on iOS 27
 
 
Q