---
url: 'https://www.corbado.com/blog/webauthn-transports-internal-hybrid'
title: 'WebAuthn Transports: Internal and Hybrid Transport'
description: 'Explore how WebAuthn transports work in browser APIs, iOS AuthenticationServices, and Android Credential Manager for cross-device passkey authentication.'
lang: 'en'
author: 'Vincent Delitz'
date: '2025-10-30T21:35:41.010Z'
lastModified: '2026-03-27T07:01:52.540Z'
keywords: 'webauthn transports'
category: 'Passkeys Implementation'
---

# WebAuthn Transports: Internal and Hybrid Transport

### Platform Transport Handling: Quick Reference

| Platform           | Platform Authenticators                                                                                                             | Security Keys    |
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------- | ---------------- |
| **Web Browsers**   | Windows Hello: `["internal"]`<br />Google Password Manager: `["internal", "hybrid"]`<br />iCloud Keychain: `["internal", "hybrid"]` | `["usb", "nfc"]` |
| **Android Native** | `["internal", "hybrid"]`                                                                                                            | `["usb", "nfc"]` |
| **iOS Native**     | ⚠️ **Empty `[]`** (iCloud Keychain)                                                                                                 | `["usb", "nfc"]` |

_Note: Per WebAuthn specification, an empty transports sequence means transport
information is unavailable or withheld for privacy. Often treated by browsers as all
transports might be possible._

## Key Facts

- **WebAuthn transports** define authenticator-to-client communication; `internal` and
  `hybrid` dominate production deployments while iOS platform authenticators uniquely
  return empty transport arrays.
- **iOS AuthenticationServices** returns empty arrays `[]` for iCloud Keychain platform
  authenticators, unlike web browsers and Android Credential Manager which report accurate
  transport data.
- The **spec-compliant approach** trusts authenticator-provided transports exactly as
  received; the optimization approach modifies `internal` and `hybrid` values to control
  which authentication UI options appear.
- In production, `["internal", "hybrid"]` patterns are most common; **hardware security
  key** transports (`usb`, `nfc`) are very rare, used primarily in enterprise or
  high-security scenarios.

## 1. Introduction: WebAuthn Transports for Cross-Device Authentication

When implementing passkeys across platforms, developers face an important decision:

- **How should you handle WebAuthn transports, especially internal and hybrid transports,
  to ensure optimal cross-device authentication experiences?**

The answer lies in understanding **WebAuthn transports**-a technical detail that
determines how [authenticators](https://www.corbado.com/glossary/authenticator) communicate with relying parties.
While transports seem straightforward in theory, their implementation varies significantly
across web browsers, native [iOS](https://www.corbado.com/blog/webauthn-errors), and native
[Android](https://www.corbado.com/blog/how-to-enable-passkeys-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:**

1. **WebAuthn transports: internal, hybrid, and platform authenticators across web, iOS,
   and Android**
2. **Two approaches: spec-compliant vs. optimized internal and hybrid transport handling**
3. **Cross-device authentication implementation best practices and recommendations**

## 2. Understanding WebAuthn Transports: Internal, Hybrid, and Platform Authenticators

### 2.1 WebAuthn Transport Types: Internal, Hybrid, USB, NFC, BLE, and Smart-Card

WebAuthn transports define the communication methods between
[authenticators](https://www.corbado.com/glossary/authenticator) and client devices. The
[WebAuthn Level 3 specification](https://www.w3.org/TR/webauthn-3/#enum-transport) defines
six transport types:

**`usb`**: Used by [hardware security keys](https://www.corbado.com/blog/best-fido2-hardware-security-keys) that
connect via USB ports, such as [YubiKeys](https://www.corbado.com/glossary/yubikey) or other
[FIDO2](https://www.corbado.com/glossary/fido2) security tokens.

**`nfc`**: Enables communication with [authenticators](https://www.corbado.com/glossary/authenticator) through
Near Field Communication, allowing users to tap their security keys or NFC-enabled
devices.

**`ble`**: Facilitates authentication via Bluetooth Low [Energy](https://www.corbado.com/passkeys-for-energy),
enabling wireless communication with external authenticators.

**`smart-card`**: Used for [smart card](https://www.corbado.com/glossary/smart-card) readers, allowing
authentication via smart cards.

**`hybrid`**: Enables cross-device authentication, typically where a user scans a
[QR code](https://www.corbado.com/blog/qr-code-login-authentication) to authenticate across devices-such as using
a phone to authenticate on a desktop browser, or vice versa. This transport can trigger
[QR code](https://www.corbado.com/blog/qr-code-login-authentication) 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](https://www.corbado.com/blog/passkeys-prf-webauthn).

**`internal`**: The [authenticator](https://www.corbado.com/glossary/authenticator) is embedded within the device
itself-like [iCloud Keychain](https://www.corbado.com/glossary/icloud-keychain) (verified via
[Face ID](https://www.corbado.com/faq/is-face-id-passkey) or Touch ID) on iPhones, Windows Hello on PCs, or
[Google Password Manager](https://www.corbado.com/blog/how-to-use-google-password-manager) on
[Android](https://www.corbado.com/blog/how-to-enable-passkeys-android) devices. These are platform
authenticators.

When a passkey is created, the [authenticator](https://www.corbado.com/glossary/authenticator) signals which
transports it supports. This information gets sent to the
[relying party](https://www.corbado.com/glossary/relying-party) (your backend), which should persist it alongside
the credential. During authentication, the [relying party](https://www.corbado.com/glossary/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.

[Watch on YouTube](https://www.youtube.com/watch?v=V1Pc4Gl0xKc)

### 2.2 Platform-Specific Behavior

Transport handling differs significantly across platforms, creating the compatibility
challenges developers face.

#### 2.2.1 Web Browsers

Browsers receive transport information from authenticators and honor it during
authentication flows. When you [create a passkey](https://www.corbado.com/blog/passkey-creation-best-practices)
in Chrome, Safari, or Edge, the browser's credential manager provides transport data that
varies based on the underlying [authenticator](https://www.corbado.com/glossary/authenticator):

**Platform authenticators**: [Windows Hello](https://www.corbado.com/glossary/windows-hello) provides
`["internal"]` only, reflecting its device-bound nature. However, when Chrome uses
[Google Password Manager](https://www.corbado.com/blog/how-to-use-google-password-manager) as the authenticator,
it provides `["internal", "hybrid"]` because
[Google Password Manager](https://www.corbado.com/blog/how-to-use-google-password-manager) supports cross-device
authentication via [Android](https://www.corbado.com/blog/how-to-enable-passkeys-android) Phones.

**Hardware security keys**: Provide specific transports like `["usb", "nfc"]` based on
their actual capabilities.

**Cloud-synced credential managers**: [iCloud Keychain](https://www.corbado.com/glossary/icloud-keychain) in
Safari and [Google Password](https://www.corbado.com/blog/how-to-use-google-password-manager) 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](https://w3c.github.io/webauthn/#sctn-issuing-cred-request-to-authenticator)

#### 2.2.2 Android Native Applications

[Android's](https://www.corbado.com/blog/how-to-enable-passkeys-android)
[Credential Manager API](https://developer.android.com/identity/sign-in/credential-manager)
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](https://developer.android.com/training/sign-in/passkeys)

#### 2.2.3 iOS Native Applications

[iOS](https://www.corbado.com/blog/webauthn-errors) presents a more complex situation. Apple's
[AuthenticationServices framework](https://developer.apple.com/documentation/authenticationservices)
handles transports differently depending on the authenticator type:

**Platform authenticators** (iCloud Keychain, verified via
[Face ID](https://www.corbado.com/faq/is-face-id-passkey) or Touch ID): Often return **empty transport arrays**
during [passkey creation](https://www.corbado.com/blog/passkey-creation-best-practices). This indicates that
transport information is unavailable or withheld for privacy-according to the WebAuthn
specification, user agents may return empty sequences when transport information is
unknown or to preserve privacy. Relying parties should treat transports as hints rather
than guarantees.

**Security keys**: Do provide transport information (e.g., `["usb"]`, `["nfc"]`) when used
with [iOS](https://www.corbado.com/blog/webauthn-errors) devices, following the expected pattern.

**Documentation**:
[Apple AuthenticationServices](https://developer.apple.com/documentation/authenticationservices/public-private_key_authentication/supporting_passkeys)

### 2.3 Transport Distribution in Production Environments

Real-world production data from web and native applications reveals the following
transport patterns, ordered by frequency. Note that these distributions are influenced by
implementation specifics and client demographics (mobile vs desktop usage, availability of
native apps), but they provide valuable insight into typical transport usage:

| Transport Pattern        | Frequency   | Source                                                                                        |
| ------------------------ | ----------- | --------------------------------------------------------------------------------------------- |
| `["internal", "hybrid"]` | Very common | Cloud-synced credential managers (iCloud Keychain, Google Password Manager) on web and native |
| `["hybrid", "internal"]` | Very common | Same as above, order variation                                                                |
| `[]` (empty array)       | Very common | iOS native platform authenticators                                                            |
| `["internal"]`           | Common      | Windows Hello, device-bound authenticators                                                    |
| `["internal", "cable"]`  | Rare        | Legacy notation for hybrid (cable = old terminology)                                          |
| `["nfc", "usb"]`         | Very rare   | Hardware security keys                                                                        |
| `["usb"]`                | Very rare   | USB-only security keys                                                                        |
| `["hybrid"]`             | Very rare   | Hybrid-only configurations                                                                    |

**Key Insights**:

**Platform authenticators dominate**: The vast majority of passkeys use `internal`
transport, often combined with `hybrid` for cross-device authentication support. This
reflects the consumer focus on platform authenticators (iCloud Keychain,
[Google Password](https://www.corbado.com/blog/how-to-use-google-password-manager) Manager).

**Empty arrays are common**: iOS native applications frequently return empty transport
arrays for platform authenticators, representing a significant portion of production
credentials. As discussed in section 2.2.3, these indicate unavailable transport
information rather than comprehensive transport support.

**Security keys are rare**:
[Hardware security keys](https://www.corbado.com/blog/best-fido2-hardware-security-keys) (`usb`, `nfc`) represent
a tiny fraction of production passkeys, indicating their primary use in enterprise or
high-security scenarios rather than consumer applications.

**Order variations exist**: The order of transports in arrays (`["internal", "hybrid"]` vs
`["hybrid", "internal"]`) varies by platform and authenticator implementation but carries
no functional difference - both indicate support for the same transport methods.

**Legacy terminology**: The `cable` transport identifier appears occasionally in older
implementations and is synonymous with `hybrid` (caBLE = cloud-assisted Bluetooth Low
[Energy](https://www.corbado.com/passkeys-for-energy), the original name for the hybrid transport).

This distribution reinforces the importance of handling `internal` and `hybrid` transports
correctly, as they account for the overwhelming majority of real-world passkey
implementations.

### 2.4 Transport Variations by Authenticator

The same authenticator often reports different transport patterns based on platform,
version, and implementation context. This variation is normal and expected:

#### Major Credential Managers

**iCloud Keychain** exhibits three patterns:

- `["internal", "hybrid"]` - Most common, typically from web browsers
- `[]` (empty array) - Very common, from iOS native apps
- `["hybrid", "internal"]` - Less common, order variation
- `["internal"]` or `["hybrid"]` alone - Rare edge cases

**Google Password Manager** shows the most variation:

- `["hybrid", "internal"]` - Most common pattern
- `["internal", "hybrid"]` - Common alternative ordering
- `["internal", "cable"]` - Legacy implementations (cable = old term for hybrid)
- `[]` (empty array) - From certain native contexts
- Single transports rarely

**Windows Hello** is most consistent:

- `["internal"]` - Dominant pattern (device-bound by design)‚

#### Third-Party Password Managers

Password managers like
[**1Password**](https://www.corbado.com/blog/3rd-party-password-manager-passkey-app-testing),
[**Bitwarden**](https://www.corbado.com/blog/3rd-party-password-manager-passkey-app-testing),
[**Dashlane**](https://www.corbado.com/blog/3rd-party-password-manager-passkey-app-testing), and
[**LastPass**](https://www.corbado.com/blog/3rd-party-password-manager-passkey-app-testing) all show similar
variation patterns:

- Both `["internal", "hybrid"]` and `["hybrid", "internal"]` orderings
- Empty arrays `[]` from [native app](https://www.corbado.com/blog/native-app-passkeys) contexts
- Occasionally just `["internal"]`

[**Samsung Pass**](https://www.corbado.com/blog/samsung-passkeys) (Android ecosystem) primarily uses:

- `["hybrid", "internal"]` and `["internal", "hybrid"]` - Both orderings common

#### Why These Variations Occur

**Platform differences**: The same authenticator behaves differently on web vs native, iOS
vs Android, or Windows vs macOS.

**Version evolution**: Transport reporting has evolved over time. Older versions may use
`cable` instead of `hybrid`, or report different combinations.

**Implementation choices**: Some authenticators prioritize `internal` first, others
`hybrid`. The order has no functional impact but varies by implementation.

**Context sensitivity**: Native apps, especially on iOS, often receive empty arrays even
from authenticators that report full transports in web contexts.

**Key Takeaway**: Don't assume transport arrays will be consistent for a given
authenticator. Design your implementation to handle all variations gracefully, focusing on
the presence of specific transports rather than exact array matching.

## 3. Two Approaches to WebAuthn Transport Handling

Developers face a choice: follow the specification strictly, or optimize internal and
hybrid transports for user experience. Each approach has merits and drawbacks.

### 3.1 Spec-Compliant Approach: Trusting Internal and Hybrid Transports

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:

```json
{
    "allowCredentials": [
        {
            "id": "credential-id-base64",
            "type": "public-key",
            "transports": ["internal", "hybrid"]
        }
    ]
}
```

**Advantages**:

- **Specification compliance**: Follows WebAuthn standards precisely, ensuring
  compatibility with future platform updates
- **Security key reliability**: Works perfectly for
  [hardware security keys](https://www.corbado.com/blog/best-fido2-hardware-security-keys) (YubiKeys, etc.) which
  always provide accurate transport information
- **Prevents invalid options**: Avoids offering authentication methods that genuinely
  aren't supported-for example, won't trigger QR codes for
  [Windows Hello](https://www.corbado.com/glossary/windows-hello) credentials

**Disadvantages**:

- **iOS empty array behavior**: Platform authenticators on iOS return empty transports,
  which indicates unavailable transport information-platforms may interpret this
  differently when determining which authentication options to show
- **May show unwanted options**: Could present [security key](https://www.corbado.com/glossary/security-key)
  options (USB, NFC) in consumer applications where they're not expected
- **Inconsistent user experience**: Different platforms offer different authentication
  options for the same account

**Best for**: Applications prioritizing standards compliance, enterprise environments with
diverse authenticator types.

### 3.2 Transport Optimization Approach: Controlling Internal and Hybrid for Cross-Device Auth

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:

#### 3.2.1 Use Case 1: Remove Security Key Options from iOS Keys

**Problem**: iOS platform authenticators return empty transport arrays. When left empty or
filled by backends, users might see [security key](https://www.corbado.com/glossary/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](https://www.corbado.com/glossary/security-key) options.

```typescript
// 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.

#### 3.2.2 Use Case 2: Prevent QR Codes on Mobile Devices

**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"]`.

```typescript
// 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:

- Some platforms show QR codes even when `hybrid` is excluded from transports
- Others hide QR codes even when `hybrid` is included
- Behavior varies significantly between Chrome, Edge, Safari, and Firefox across Windows,
  macOS, and iOS

**Risk 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.

#### 3.2.3 Important Considerations

**These are optimization hints**: WebAuthn provides other mechanisms to optimize
authentication UX beyond transport manipulation-such as
[hints](https://www.w3.org/TR/webauthn-3/#enum-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:

- **iOS**: Sends empty arrays for platform authenticators; requires filling
- **Windows Hello**: Must remain `["internal"]` only; adding `hybrid` triggers unwanted QR
  codes
- **Web & Android**: Generally provide accurate transport information
- **CDA variations**: [QR code](https://www.corbado.com/blog/qr-code-login-authentication) prompts may appear or
  disappear regardless of `hybrid` presence in transports array

**End-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**:

- **Tailored UX**: Control exactly which authentication options users see in specific
  contexts
- **Solves iOS empty array issue**: Explicitly defines transports where iOS provides none
- **Context-aware optimization**: Adapt authentication UI based on device type

**Disadvantages**:

- **Unpredictable behavior**: Transport manipulation doesn't guarantee consistent UI
  behavior-extensive testing shows platforms interpret transports differently, sometimes
  showing or hiding options regardless of transport values
- **Risk of authentication deadends**: Overly restrictive transport filtering can prevent
  users from authenticating entirely, especially in cross-device scenarios
- **Deviates from specification**: Moves away from spec recommendations, potentially
  causing issues with future platform changes
- **Maintenance burden**: Requires ongoing platform-specific logic and updates as
  platforms evolve
- **Complexity**: Must handle iOS empty arrays, [Windows Hello](https://www.corbado.com/glossary/windows-hello)
  constraints, and other platform quirks manually
- **Testing overhead**: Every optimization rule needs verification across all platform
  combinations

**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.

### 3.3 WebAuthn Transport Strategy: Platform Authenticators and Cross-Device Authentication

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.

#### 3.3.1 Strategy 1: Maximum Standard Conformity & User Freedom

This approach prioritizes flexibility and standards compliance, allowing users to
authenticate with any compatible authenticator.

**Implementation Characteristics**:

- **Authentication UI**: [Passkey button](https://www.corbado.com/blog/passkey-login-best-practices) appears
  alongside existing login options (username/password)
- **allowCredentials**: Set to empty array `[]`, allowing any credential to match
- **Authenticator types**: Security keys, cross-device authentication (QR codes), platform
  authenticators all supported
- **Native app requirements**: Must support all authentication methods, including security
  keys
- **preferImmediatelyAvailableCredentials**: Cannot be used, as it excludes security keys
  and QR code logins by definition
- **Transport handling**: Must accommodate all transport types, including security key
  transports (`usb`, `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.

#### 3.3.2 Strategy 2: Consumer-Tailored Platform Authenticators

This approach optimizes for consumer UX by restricting
[passkey creation](https://www.corbado.com/blog/passkey-creation-best-practices) to platform authenticators and
using identifier-first flows.

**Implementation Characteristics**:

- **Passkey creation**: User-initiated nudges (post-login prompts, automatic creation
  flows) use `authenticatorAttachment: "platform"` to focus on immediately available
  authenticators
- **Security key support**: Available via web account settings without
  `authenticatorAttachment` restriction, allowing power users to select any authenticator
  including security keys
- **Authentication flow**: Identifier-first-users enter email/username before
  authentication
- **allowCredentials**: Populated with user's specific credentials (not empty) once
  identifier is known
- **Authenticator types**: Platform authenticators and cross-device authentication
  prioritized; security keys supported but not promoted in primary flows
- **Native app optimization**: Uses `preferImmediatelyAvailableCredentials` for silent,
  instant authentication without prompts for security keys or QR codes
- **Cross-device authentication**: Available on web; intentionally excluded in native apps
  when using `preferImmediatelyAvailableCredentials` (users typically authenticate on the
  device where their passkeys reside)
- **Transport handling**: Primary focus on `internal` and `hybrid` transports

**Transport Implications**:

Since `allowCredentials` contains specific credentials with their transports, transport
handling becomes crucial for optimizing authentication experiences.

**Security Key Reality**: Security keys represent an extremely small fraction of passkey
usage in [large-scale](https://www.corbado.com/blog/introducing-passkeys-large-scale-overview) consumer
deployments-primarily power users or users with specific security requirements. The
consumer-tailored approach acknowledges this reality by supporting security keys without
optimizing primary flows around them.

**Two-Tier Creation Strategy**: Implementations can balance security key compatibility
with optimized consumer UX through dual creation paths:

- **User nudges and prompts**: Post-login prompts and automatic creation flows use
  `authenticatorAttachment: "platform"`, guiding users toward immediately available
  passkeys with high success rates
- **Web account settings**: Offers creation without `authenticatorAttachment`, allowing
  power users to select security keys, third-party password managers, or any available
  authenticator

This pattern appears in major implementations: security keys are supported and functional
via settings, but user-facing nudges optimize for the dominant use case-platform
authenticators that provide instant, silent authentication.

**Best for**: Consumer applications, native mobile apps, scenarios prioritizing
streamlined UX over authenticator flexibility, platforms where identifier-first flows
already exist.

#### 3.3.3 Comparison Matrix

| Characteristic                | Standard Conformity                | Consumer-Tailored                                       |
| ----------------------------- | ---------------------------------- | ------------------------------------------------------- |
| **allowCredentials**          | Empty array                        | User-specific credentials                               |
| **Authenticator types**       | All (platform, security keys, CDA) | Platform + CDA (primary), security keys (via settings)  |
| **Native app API**            | Standard WebAuthn                  | preferImmediatelyAvailableCredentials                   |
| **Security keys**             | Supported in all flows             | Supported via settings                                  |
| **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 primary flows, power user options available |
| **Implementation complexity** | Lower                              | Higher (context-aware transport logic)                  |
| **Consumer friction**         | Higher (multiple auth choices)     | Lower (optimized for dominant use cases)                |

#### 3.3.4 Identifier-First Flows and Account Enumeration

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:

1. Backend queries for existing passkeys
2. Returns `allowCredentials` with specific credentials and their transports
3. Platform can optimize authentication UI based on transports
4. No additional [account enumeration](https://www.corbado.com/faq/account-enumeration-risk-passkeys) risk
   (identifier already provided)

In 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](https://www.corbado.com/blog/passkeys-biometric-authentication).

## 4. WebAuthn Transport Implementation Best Practices

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](https://www.corbado.com/blog/webauthn-user-id-userhandle)
and public key. This data is essential for authentication flows.

**Handle Empty Arrays Gracefully**: When receiving an empty transport array from iOS
platform authenticators:

- **Spec-compliant**: Leave empty or omit transports property-indicates transport
  information is unavailable; platforms will determine available options
- **Optimization approach**: Fill with `["internal", "hybrid"]` to control which
  authentication options are shown

**Web vs Native Transport Strategies**: Differentiate transport handling based on context:

- **Web authentication**: Include all transports, allowing broader authenticator support
  including security keys via USB/NFC
- **Native app authentication**: Use `preferImmediatelyAvailableCredentials` for silent
  authentication; transports sent as stored
- **Settings/management pages**: Support all authenticator types for power users

**Handle Security Key Authentication**: When users have security keys registered:

- **Web**: Detect security key transports in stored credentials and ensure authentication
  flows can accommodate them
- **Native apps**: Consider providing fallback authentication methods or directing users
  to web for security key authentication
- **Hybrid approach**: Native apps optimize for platform authenticators while web supports
  full authenticator flexibility

**Test Across All Target Platforms**: Create a testing matrix covering all combinations:

- Registration: Web, iOS Native, Android Native
- Authentication: Web, iOS Native, Android Native
- Verify silent authentication works with `preferImmediatelyAvailableCredentials`
- Confirm security keys work in settings flows without `authenticatorAttachment`
- Validate QR codes appear only in appropriate contexts

**Understand Transport Semantics**: Recognize the differences between empty and missing
transport values:

- **Empty transports array `[]`**: Indicates transport information is unavailable or
  withheld for privacy. User agents may provide empty sequences when they cannot or choose
  not to report transport capabilities. This is not equivalent to "all transports
  supported"-treat as hints where information is unavailable.
- **Missing transports property**: When transports are omitted from credential
  descriptors, user agents determine available authentication methods based on other
  factors. Context matters: in registration responses vs authentication request options,
  the implications differ.
- **Transport hints**: Per specification, transports should be treated as hints to help
  user agents optimize authentication UI, not as authoritative guarantees of capabilities.

**Monitor Platform Changes**: WebAuthn implementations evolve. Apple, Google, and
Microsoft regularly update their authenticator behaviors. Stay informed about changes that
might affect transport handling.

## 5. Conclusion: Choosing Your WebAuthn Transport Strategy

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.

### 5.1 Key Takeaways

**Transport Decisions Live Within Broader Strategy**: How you handle transports depends on
whether you're building for maximum flexibility (empty
[allowCredentials](https://www.corbado.com/glossary/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](https://www.corbado.com/faq/account-enumeration-risk-passkeys) concerns.

### 5.2 Choosing Your Strategy

**For Enterprise / Maximum Flexibility**:

- Use empty `allowCredentials` to support all authenticator types
- Trust authenticator-provided transports
- Accept that users see more authentication options
- Simpler implementation, broader compatibility

**For Consumer Applications / Native Apps**:

- Implement
  [identifier-first authentication flow](https://www.corbado.com/blog/passkey-implementation-password-managers)
- User nudges (post-login, automatic prompts): Use `authenticatorAttachment: "platform"`
  for high-success immediate authentication
- Web account settings: Allow creation without `authenticatorAttachment` for power users
  needing security keys
- Use `allowCredentials` with specific credentials and optimized transports
- Native apps: Enable `preferImmediatelyAvailableCredentials` for silent authentication
- Fill iOS empty arrays with `["hybrid", "internal"]`
- Web authentication: Support all transports including security keys
- Filter `hybrid` on mobile devices to prevent QR codes where appropriate
- Superior UX with streamlined authentication options while maintaining compatibility

**For Platforms with Identifier-First Flows Already**:

- [Account enumeration](https://www.corbado.com/faq/account-enumeration-risk-passkeys) is already a non-issue
- Consumer-tailored approach aligns naturally with existing UX
- Transport optimization provides immediate UX benefits
- **Recommended approach** for most consumer applications

### 5.3 Implementation Recommendation

**Start spec-compliant**, then optimize based on your strategy:

1. Persist transports exactly as received during registration
2. Decide your overall strategy (maximum flexibility vs. consumer-tailored)
3. If consumer-tailored: implement identifier-first flow and optimize transports
4. Handle iOS empty arrays appropriately for your chosen strategy
5. Test thoroughly across Web, iOS Native, and Android Native platforms

The WebAuthn landscape continues evolving. Platform vendors regularly update their
implementations, and specifications like [WebAuthn Level 3](https://www.corbado.com/blog/passkeys-prf-webauthn)
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.

## Frequently Asked Questions

### Why does iOS return empty transport arrays during passkey registration?

iOS AuthenticationServices withholds transport information for platform authenticators
like iCloud Keychain, returning empty arrays per WebAuthn spec privacy provisions.
Security keys on iOS do provide transport data such as `["usb"]` or `["nfc"]`. Relying
parties should treat all transports as hints rather than authoritative guarantees of
capability.

### What is the difference between `cable` and `hybrid` transport in WebAuthn?

`cable` is legacy terminology synonymous with `hybrid`, standing for caBLE (cloud-assisted
Bluetooth Low Energy). Both describe cross-device authentication such as scanning a QR
code to authenticate a desktop session using a phone. `hybrid` is the current term
introduced in WebAuthn Level 3 and should be used in new implementations.

### How should I fill empty transport arrays from iOS platform authenticators in my allowCredentials list?

For consumer applications using identifier-first flows, explicitly set transports to
`["hybrid", "internal"]` for iOS platform authenticators that returned empty arrays during
registration. This prevents USB and NFC security key prompts from appearing in
authentication UI. The spec-compliant alternative is to leave arrays empty or omit the
transports property entirely.

### When should I filter out hybrid transport from allowCredentials on mobile devices?

Removing `hybrid` transport on mobile prevents QR code prompts when users are already on a
device where their passkeys reside. However, transport manipulation produces inconsistent
results: some platforms show QR codes even when `hybrid` is excluded, and others hide them
regardless. Always test across target platforms and provide fallback authentication
methods to avoid creating deadends.

### What is the difference between using an empty allowCredentials array versus populating it with specific credentials for passkey authentication?

An empty `allowCredentials` array supports all authenticator types including security keys
and cross-device authentication, but reduces transport relevance and may present users
with multiple simultaneous options. Populating it with specific user credentials makes
transport handling critical for optimizing UI, enabling identifier-first flows to filter
QR codes on mobile and hide security key prompts in consumer contexts.
