Explore how WebAuthn transports work in browser APIs, iOS AuthenticationServices, and Android Credential Manager for cross-device passkey authentication.

Vincent
Created: October 30, 2025
Updated: October 30, 2025

Passkeys for Super Funds and Financial Institutions
Join our Webinar on 7th November to learn how Super Funds and Financial Institutions can implement passkeys
| Platform | Platform Authenticators | Security Keys | 
|---|---|---|
| Web Browsers | Windows Hello: ["internal"]Google Password Manager: ["internal", "hybrid"]iCloud Keychain: ["internal", "hybrid"] | ["usb", "nfc"] | 
| Android Native | ["internal", "hybrid"] | ["usb", "nfc"] | 
| iOS Native | ⚠️ Empty [](iCloud Keychain) | ["usb", "nfc"] | 
Note: Per WebAuthn specification, empty transports means all transports are supported.
When implementing passkeys across platforms, developers face an important decision:
The answer lies in understanding WebAuthn transports-a technical detail that determines how authenticators communicate with relying parties. While transports seem straightforward in theory, their implementation varies significantly across web browsers, native iOS, and native Android applications, particularly for internal and hybrid transport handling.
This article examines how WebAuthn transports work across different platforms and presents two distinct approaches to handling internal and hybrid transports-each with its own trade-offs.
This article covers:
WebAuthn transports define the communication methods between authenticators and client devices. The WebAuthn Level 3 specification defines six transport types:
usb: Used by hardware security keys that connect via USB ports, such as YubiKeys or other FIDO2 security tokens.
nfc: Enables communication with authenticators through Near Field Communication, allowing users to tap their security keys or NFC-enabled devices.
ble: Facilitates authentication via Bluetooth Low Energy, enabling wireless communication with external authenticators.
smart-card: Used for smart card readers, allowing authentication via smart cards.
hybrid: Enables cross-device authentication, typically where a user scans a QR code to authenticate across devices-such as using a phone to authenticate on a desktop browser, or vice versa. This transport can trigger QR code prompts on both desktop and mobile devices, which may not always be desirable depending on the context. Note: hybrid was added in WebAuthn Level 3.
internal: The authenticator is embedded within the device itself-like iCloud Keychain (verified via Face ID or Touch ID) on iPhones, Windows Hello on PCs, or Google Password Manager on Android devices. These are platform authenticators.
When a passkey is created, the authenticator signals which transports it supports. This information gets sent to the relying party (your backend), which should persist it alongside the credential. During authentication, the relying party sends these transports back to the client in the allowCredentials list, helping the browser or platform determine which authentication methods to offer the user.
Transport handling differs significantly across platforms, creating the compatibility challenges developers face.
Browsers receive transport information from authenticators and honor it during authentication flows. When you create a passkey in Chrome, Safari, or Edge, the browser's credential manager provides transport data that varies based on the underlying authenticator:
Platform authenticators: Windows Hello provides ["internal"] only, reflecting its device-bound nature. However, when Chrome uses Google Password Manager as the authenticator, it provides ["internal", "hybrid"] because Google Password Manager supports cross-device authentication via Android Phones.
Hardware security keys: Provide specific transports like ["usb", "nfc"] based on their actual capabilities.
Cloud-synced credential managers: iCloud Keychain in Safari and Google Password Manager in Chrome typically provide ["internal", "hybrid"] to support both local and cross-device authentication flows.
This information flows reliably in web contexts, though the specific transports depend on which authenticator the browser selects for credential storage.
Documentation: W3C WebAuthn Specification
Android's Credential Manager API behaves similarly to web browsers. When creating passkeys in native Android apps, the Credential Manager provides transport information that mirrors web behavior-platform authenticators report their capabilities accurately, and the system handles transport data consistently. Android developers can rely on this information without special handling.
Documentation: Android Credential Manager
iOS presents a more complex situation. Apple's AuthenticationServices framework handles transports differently depending on the authenticator type:
Platform authenticators (iCloud Keychain, verified via Face ID or Touch ID): Often return empty transport arrays during passkey creation. This doesn't mean the passkey lacks transport capabilities-it simply means iOS doesn't report them explicitly. According to the WebAuthn standard, leaving out transports means any transport is acceptable, so hybrid authentication will still work.
Security keys: Do provide transport information (e.g., ["usb"], ["nfc"]) when used with iOS devices, following the expected pattern.
Documentation: Apple AuthenticationServices
Developers face a choice: follow the specification strictly, or optimize internal and hybrid transports for user experience. Each approach has merits and drawbacks.
This approach aligns with the WebAuthn specification: use transports exactly as provided by the authenticator during credential registration, and send them back unchanged during authentication.
Implementation: When a passkey is created, persist the transports array from the authenticator response. During authentication, include these exact transports in the allowCredentials list:
{ "allowCredentials": [ { "id": "credential-id-base64", "type": "public-key", "transports": ["internal", "hybrid"] } ] }
Advantages:
Disadvantages:
Best for: Applications prioritizing standards compliance, enterprise environments with diverse authenticator types.
This approach prioritizes user experience by selectively modifying internal and hybrid transports based on specific optimization goals. Rather than a blanket rule, consider these common optimization scenarios:
Problem: iOS platform authenticators return empty transport arrays. When left empty or filled by backends, users might see security key prompts (USB, NFC) alongside platform options, creating confusion in consumer applications.
Solution: Explicitly set transports to ["hybrid", "internal"] for iOS platform authenticators. This ensures only platform authentication and cross-device flows are offered, hiding security key options.
// When persisting iOS platform authenticator credentials if (platform === "iOS" && authenticatorAttachment === "platform") { transports = ["hybrid", "internal"]; }
Result: Clean authentication UI without security key prompts for iOS-created passkeys.
Problem: When authenticating on mobile devices, showing QR codes for cross-device authentication creates poor UX-users are already on a mobile device with their passkeys available.
Solution: Remove hybrid transport when the user is authenticating from a mobile device, leaving only ["internal"].
// When building allowCredentials for authentication const transports = isMobileDevice ? credentials.transports.filter(t => t !== "hybrid") : credentials.transports;
Result: Mobile users see only direct authentication options without unnecessary QR code prompts.
⚠️ Caution: Transport manipulation doesn't always produce consistent results across platforms. Extensive testing shows that browser and OS combinations handle transports differently:
hybrid is excluded from transportshybrid is includedRisk of deadends: Overly restrictive transport filtering can create authentication deadends where users cannot log in at all. For example, removing hybrid might prevent legitimate cross-device authentication scenarios where a user needs to authenticate from a borrowed device. Always provide fallback authentication methods and test thoroughly across your target platforms before deploying transport optimizations.
These are optimization hints: WebAuthn provides other mechanisms to optimize authentication UX beyond transport manipulation-such as hints.
Transport behavior is unpredictable: Cross-device authentication (CDA) via hybrid transport exhibits inconsistent behavior across browser and OS combinations. Real-world testing demonstrates that transport values don't guarantee specific UI behavior-platforms interpret and handle transports differently, leading to unexpected results.
Platform-specific complexity: When explicitly controlling transports, you must account for platform differences:
["internal"] only; adding hybrid triggers unwanted QR codeshybrid presence in transports arrayEnd-to-end understanding required: Explicitly controlling transports means taking responsibility for the entire flow. You must understand how each transport combination behaves across all your target platforms and test thoroughly. Transport manipulation can create authentication deadends where no valid authentication path exists for users.
Advantages:
Disadvantages:
Best for: Consumer applications with specific UX requirements, teams with resources to maintain platform-specific logic, scenarios prioritizing streamlined authentication flows over strict spec compliance.
WebAuthn transport handling doesn't exist in isolation-it's one piece of your overall passkey implementation strategy. Two common approaches emerge in production deployments, each with different implications for internal and hybrid transport usage.
This approach prioritizes flexibility and standards compliance, allowing users to authenticate with any compatible authenticator.
Implementation Characteristics:
[], allowing any credential to matchusb, nfc, ble)Transport Implications:
With empty allowCredentials, transports become less critical during authentication-the platform shows all available options. However, this means users may see security key prompts, QR codes, and platform options simultaneously, which can create decision paralysis in consumer applications.
Best for: Enterprise environments, applications with diverse user bases requiring security key support, scenarios prioritizing maximum authentication flexibility.
This approach optimizes for consumer UX by restricting passkey creation to platform authenticators and using identifier-first flows.
Implementation Characteristics:
authenticatorAttachment: "platform"preferImmediatelyAvailableCredentials, which excludes security keys and cross-device authentication by definitionpreferImmediatelyAvailableCredentials in native apps, but this scenario is rare (users typically have passkeys on the device they're using)internal and hybrid transports onlyTransport Implications:
Since allowCredentials contains specific credentials with their transports, transport handling becomes crucial.
Best for: Consumer applications, native mobile apps, scenarios prioritizing streamlined UX over authenticator flexibility, platforms where identifier-first flows already exist.
| Characteristic | Standard Conformity | Consumer-Tailored | 
|---|---|---|
| allowCredentials | Empty array | User-specific credentials | 
| Authenticator types | All (platform, security keys, CDA) | Platform + CDA | 
| Native app API | Standard WebAuthn | Can use preferImmediatelyAvailableCredentials | 
| Security keys | Supported | Typically excluded | 
| Transport relevance | Low (empty allow list) | High (specific credentials) | 
| Mobile QR codes | May appear | Can be optimized away | 
| User experience | More options, more complexity | Streamlined, fewer decisions | 
| Implementation complexity | Lower | Higher | 
| Consumer friction | Higher (multiple auth choices) | Lower (optimized for consumer flows) | 
For platforms that already leak account existence or use identifier-first flows (user enters email before seeing login options), the consumer-tailored approach aligns naturally. Once the user has provided their identifier:
allowCredentials with specific credentials and their transportsIn these scenarios, transports can become optimization tool rather than a security concern. You can tailor authentication options based on device context (mobile vs. desktop) and credential capabilities.
Recommendation: For platforms that already use identifier-first flows or where account enumeration isn't a concern, the consumer-tailored approach with explicit transport handling provides superior UX, especially in native mobile applications where preferImmediatelyAvailableCredentials enables seamless biometric authentication.
Regardless of which approach you choose for handling internal and hybrid transports, follow these practices to minimize issues:
Persist Transports During Registration: Always store the transports array from the authenticator response alongside the credential ID and public key. This data is essential for authentication flows.
Handle Empty Arrays Gracefully: When receiving an empty transport array from iOS platform authenticators:
["internal", "hybrid"] to control which authentication options are shownTest Across All Target Platforms: Create a testing matrix covering all combinations:
Understand Empty Array vs. Missing Property: Both an empty transports array [] and a missing transports property are typically treated as "any transport is acceptable" according to the specification. However, implementation details vary across platforms.
Monitor Platform Changes: WebAuthn implementations evolve. Apple, Google, and Microsoft regularly update their authenticator behaviors. Stay informed about changes that might affect transport handling.
WebAuthn transports-especially internal and hybrid transports-are technical details with significant practical impact on cross-device authentication. Your transport handling strategy should align with your broader passkey implementation approach and target platforms.
Transport Decisions Live Within Broader Strategy: How you handle transports depends on whether you're building for maximum flexibility (empty allowCredentials) or consumer UX (identifier-first with specific credentials). The latter makes transports critical for optimization.
Platform Differences Require Handling: Web and Android provide reliable transport information, while iOS platform authenticators return empty arrays. Windows Hello sends only ["internal"]. Understanding these differences is essential for production deployments.
Two Valid Transport Approaches: Spec-compliant (trust authenticator transports) works well for enterprise and maximum flexibility scenarios. Explicit control (optimize transports) suits consumer applications with identifier-first flows and native mobile apps.
Identifier-First Enables Transport Optimization: When users provide their identifier first, transport handling becomes a powerful UX tool. You can prevent unwanted QR codes on mobile, hide security key options, and streamline authentication-without additional account enumeration concerns.
For Enterprise / Maximum Flexibility:
allowCredentials to support all authenticator typesFor Consumer Applications / Native Apps:
authenticatorAttachment: "platform")allowCredentials with specific credentials and optimized transportspreferImmediatelyAvailableCredentials in native apps["hybrid", "internal"]hybrid on mobile devices to prevent QR codesFor Platforms with Identifier-First Flows Already:
Start spec-compliant, then optimize based on your strategy:
The WebAuthn landscape continues evolving. Platform vendors regularly update their implementations, and specifications like WebAuthn Level 3 introduce new capabilities. Building flexible systems that align transport handling with your broader authentication strategy ensures your passkey implementation remains robust and provides excellent user experiences as the ecosystem matures.
Related Articles
Table of Contents