Skip to content

fix(ios): create() presents both providers when authenticatorAttachment is unset (like get()) - #67

Open
enda-kelly wants to merge 1 commit into
peterferguson:mainfrom
enda-kelly:fix/ios-create-both-providers
Open

fix(ios): create() presents both providers when authenticatorAttachment is unset (like get())#67
enda-kelly wants to merge 1 commit into
peterferguson:mainfrom
enda-kelly:fix/ios-create-both-providers

Conversation

@enda-kelly

@enda-kelly enda-kelly commented Aug 5, 2026

Copy link
Copy Markdown

What

On iOS, create() (registration) presents a single authenticator provider. get()
(authentication) presents both. Because of this, an app can offer a security key at sign-in but not
when a user adds a passkey.

This change makes create() mirror get(). When the request does not set authenticatorAttachment,
it submits both the platform request and the security-key request to one ASAuthorizationController.
iOS then shows a combined sheet, so the user can register a platform passkey or a security key. This
matches navigator.credentials.create() on the web. When the request sets an attachment (platform
or cross-platform), the behaviour does not change.

The credential building already exists. prepareCrossPlatformRegistrationRequest(...) already maps
pubKeyCredParams, residentKey, userVerification, attestation, and excludeCredentials. So
this is only a control-flow change.

Tested on a device

I built an app with this change and ran it on a device (iOS 26.5.2, Expo SDK 57). create() with no
pinned attachment shows a combined registration sheet. A YubiKey 5 FIPS enrols end to end (PIN and
touch) over USB-C. ASAuthorizationController accepts two registration requests, as it already does
for assertions.

Compatibility

Behaviour change: apps that send no authenticatorAttachment will start to show security-key options
at registration, where today they get a platform-only sheet. This matches the web default, but it is
visible. A minor release with a changelog note is probably appropriate.

Android is not affected. Credential Manager presents the provider choice itself.

Related: #34 (navigator.credentials.get/create API parity), and #68 (the lone-request non-completion that presenting both providers avoids).

Summary by CodeRabbit

  • New Features
    • Passkey registration now supports both cross-platform and platform authenticators when no specific authenticator type is requested.
    • Registration requests can select the appropriate authenticator based on the selected attachment preference.

…nt is unset

Match get(): submit both the platform and the security-key registration requests to one
ASAuthorizationController when the request does not pin authenticatorAttachment, so iOS shows a
combined sheet. A pinned attachment keeps the single-provider behaviour.
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: e5549460-aaa7-44b4-a09d-9ca23b88b36b

📥 Commits

Reviewing files that changed from the base of the PR and between 4a95249 and af855ec.

📒 Files selected for processing (1)
  • ios/ReactNativePasskeysModule.swift

📝 Walkthrough

Walkthrough

iOS registration now selects platform and cross-platform providers independently. When no attachment is specified, both eligible requests are combined in one authorization controller.

Changes

iOS registration provider selection

Layer / File(s) Summary
Combine eligible registration requests
ios/ReactNativePasskeysModule.swift
The module includes each provider unless the requested authenticatorAttachment excludes it. It submits all non-nil requests through one authorization controller.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related issues

  • Issue 68 — The combined platform and cross-platform registration requests address the related iOS security-key flow issue.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the iOS create() change to present both providers when authenticatorAttachment is unset.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant