Cross-Platform Browser Behaviour
“Does this browser support passkeys?” is not a question with a single answer, because the behaviour a user experiences is produced by a browser engine, an operating system, a credential provider and possibly an enterprise policy — four independent layers that can each change the outcome. This page covers what is genuinely universal, what varies, and how to build a support picture from your own traffic rather than from a table. It sits under Frontend UX and Conditional Mediation.
Concept Definition and Spec Grounding
The parts of WebAuthn defined tightly enough to behave identically everywhere are the security-critical ones. Origin binding works the same way on every platform, because the browser enforces it and the rule is unambiguous. The assertion signature covers the same bytes and verifies the same way. The challenge is single-use wherever your server makes it so. The DOMException names are the same coarse set, deliberately uninformative in the same way.
What varies is everything above that layer: how credentials are stored, which of them a chooser offers, whether an autofill surface exists at all, how the cross-device flow is presented, and how much a platform is willing to say about the authenticator. None of that is specified in a way that would produce identical behaviour, and none of it needs to be — a relying party’s correctness does not depend on any of it.
The practical consequence is a design rule. Anything your security depends on is universal, so build on it directly. Anything about presentation varies, so treat every part of it as an enhancement with a fallback. Deployments that get into trouble have usually inverted this: they depend on a presentation behaviour and treat a universal one as though it needed a workaround.
Architecture and Data Flow
The four layers interact in a fixed order. The browser exposes the API and decides which mediation modes it implements. The operating system provides the credential store and, where one exists, the autofill surface. The credential provider — the platform’s own keychain or a third-party manager the user installed — decides which credentials are offered and how. Enterprise policy, where present, can restrict or disable any of the three.
Because the layers are independent, capability does not compose the way people expect. A current browser on an older operating system may report conditional-mediation support and produce nothing useful, because the autofill surface belongs to the OS. A browser with no built-in authenticator can still complete a ceremony via the cross-device flow, because the credential lives on a phone. A managed browser may report everything as available and refuse the ceremony on policy grounds.
This is why runtime probing is authoritative and static tables are advisory. The probe asks the actual stack in front of you; a table describes a combination somebody tested once.
Implementation Guide
Step 1 — build on the universal layer. Origin binding, signature verification, single-use challenges. None of these need platform-specific handling, and code that adds any is usually working around a bug elsewhere.
Step 2 — probe at runtime, never sniff. The three probes — API presence, platform-authenticator availability, conditional-mediation support — answer the questions a user-agent string cannot.
Step 3 — treat every presentation behaviour as optional. Autofill may not appear. The chooser may look unfamiliar. The cross-device flow may be presented differently. All of these must degrade to a working page rather than a broken one.
Step 4 — record platform context with ceremony outcomes. Browser name and major version, operating system version, and the ceremony result. Three fields, and they turn “the rate went up” into “one platform changed”.
Step 5 — segment completion rate by platform. The number that matters is not capability but whether ceremonies finish, and it varies enough between platforms to be worth watching separately.
Step 6 — revisit quarterly. Platform behaviour moves at the pace of OS releases. A picture assembled a year ago describes a population that has largely updated.
Validation Checklist
Error Reference Table
| Observation | Likely layer | What to do |
|---|---|---|
| Probe true, dropdown empty | credential provider or no credential | check enrolment, not capability |
| Ceremonies fail on one browser after a release | browser engine | compare against the release notes; adapt |
| Failures confined to one customer’s network | enterprise policy or relay blocking | keep the password path visible |
| Autofill works, chooser looks unfamiliar | credential provider | nothing — it is the user’s manager |
| Cross-device flow stalls after scanning | proximity or relay | explain Bluetooth; keep timeouts generous |
| Everything fails in an embedded web view | platform restriction | use native credential APIs instead |
Platform and Library Notes
The largest differences a relying party notices are in autofill and in the cross-device flow, and both are presentation rather than protocol. Autofill availability depends on the operating system as much as the browser, so a support statement that names only browsers will mispredict. The cross-device flow differs in how it is offered — sometimes as a prominent option, sometimes behind a secondary menu — which changes how discoverable it is for a user standing at an unfamiliar machine.
Third-party credential managers add a layer that is invisible from your code but very visible to the user, since the chooser and its behaviour become the manager’s rather than the platform’s. Nothing in your implementation changes, but user reports will describe an interface you have never seen.
Embedded web views are the one environment worth treating as categorically different. Origin rules still apply, but a shell loading content without a proper origin has no registrable domain and WebAuthn simply refuses. Native surfaces should use the platform credential APIs with an associated-domains file rather than attempting a browser ceremony.
Pitfalls and Security Hardening
1. A user-agent support table. Out of date the day it is written, and blind to the operating system and credential provider entirely.
2. Depending on autofill. It is the best experience available and it is not universal. The explicit button is what makes the page work everywhere.
3. Hiding the cross-device option. It is the flow that rescues a user on a machine that is not theirs, which is exactly when they most need rescuing.
4. Treating an embedded web view as a browser. It will fail, and the fix is a different API rather than a workaround.
5. Assuming enterprise environments behave like consumer ones. Policy can disable the whole feature, and those users are frequently the ones you can least afford to strand.
6. Building platform-specific code paths for security checks. Anything security-critical is universal; a platform branch there is a sign that something else was misdiagnosed.
Frequently Asked Questions
Is there a browser that does not support passkeys at all?
Current versions of the major engines all implement the credential API, so the meaningful variation is in the layers above it — whether an autofill surface exists, whether a built-in authenticator is present, and whether policy permits use. Older builds, embedded web views and locked-down environments are where a complete absence still shows up.
Why does the same code behave differently on two machines with the same browser?
Because the operating system version, the credential provider and any enterprise policy differ, and all three affect the outcome. This is the single most common source of “it works on my machine” in passkey work, and it is why the probes have to run at runtime rather than being inferred.
Should I maintain a compatibility table for my team?
Yes, built from your own telemetry rather than copied from elsewhere. A table showing completion rate by browser and operating system version, refreshed quarterly, answers the questions that actually come up — whether to promote the passkey path, and which platform to investigate.
Does the cross-device flow work everywhere?
The mechanism is broadly available, but it depends on Bluetooth being enabled on both devices and on outbound access to a relay service. Restrictive networks block the second, which produces a scan that succeeds followed by a ceremony that never completes.
How should embedded surfaces be handled?
With the platform’s native credential APIs and an associated-domains configuration, not with a browser ceremony inside a web view. The RP ID stays your web domain, so credentials are shared between the app and the site, but the API is different.
What is worth testing manually per release?
One platform authenticator, one security key, and one cross-device flow. Ten minutes, and between them they cover the behaviours no automation can reach.
Reading a Platform Difference Correctly
When a behaviour differs between platforms, the useful first question is which of the four layers produced it, because the answer determines whether there is anything you can do.
Engine differences show up as a change confined to one browser, often after a release, and affecting every operating system that browser runs on. These are the ones worth adapting to: a stricter interpretation of user activation, a change in how a mediation mode behaves, a new validation on an option you send. They are also the ones that appear in release notes, so a difference that correlates with a version bump usually has a documented cause.
Operating system differences show up as a change confined to one platform across every browser on it, and they are most visible in autofill. A browser can implement conditional mediation perfectly and still show nothing, because the surface that would display the suggestion belongs to the OS. There is rarely anything to fix here; the correct response is that the explicit button covers it.
Credential provider differences show up as an unfamiliar chooser and as credentials appearing or not appearing in ways that do not match the platform default. A user with a third-party manager is having a different experience from the one you tested, and none of it is under your control. The signal that distinguishes it is that the same device behaves differently for two users.
Policy differences show up as failures concentrated in one organisation, one network, or one managed device fleet, with no version correlation at all. These are the ones most likely to be reported as “your site is broken” and least likely to be reproducible, and the only reliable mitigation is that the password path remains reachable.
Working through those four in order takes minutes and usually identifies the layer before any code is read, which is a better use of an investigation than starting from the assumption that something in your own implementation changed.
What to Do When a Platform Changes
Platform behaviour moves, and a passkey deployment that is not watching for it will discover a change through support tickets rather than through telemetry.
Watch completion rate segmented by platform and major version. A step change confined to one segment, beginning on a specific date, is the signature of a platform update, and it is visible in aggregate long before anybody reports it individually. Watching the aggregate alone hides it, because a change affecting one platform is diluted by every other.
Watch the mediation mix. A shift in how many ceremonies are armed conditionally versus started from the explicit button usually means an autofill surface has changed availability, and it is often the first visible sign of an operating system release reaching your users.
Watch the error name distribution rather than the total. A rise in NotAllowedError concentrated in short elapsed times means something is now refusing ceremonies before the prompt — frequently a tightened activation rule — while the same rise spread across longer elapsed times is ordinary user behaviour.
When a change is confirmed, the response is almost always to adapt rather than to work around. Platform changes in this area are generally tightening security or improving the user experience, and code written to defeat them tends to break at the next release. The exception is a regression, which is worth reporting upstream and working around temporarily behind a flag you can remove.
Keep a short record of what changed and when. A passkey deployment accumulates a handful of these over a couple of years, and the record is what stops the team re-diagnosing the same platform behaviour a second time.
Supporting Users Across Platforms
Support conversations about passkeys have a characteristic shape, and preparing for it saves a great deal of back-and-forth.
The most common report is “my passkey has disappeared”, and it almost never means what it says. In the majority of cases the credential exists and the user is on a device that cannot reach it — a desktop machine when the passkey lives on a phone, a different browser profile, or a work device where policy blocks the credential provider. The productive first question is not about the passkey but about the device: is this the machine you set it up on. Building the cross-device option prominently into the sign-in page removes most of these before they become contacts.
The second most common is “it asked for my fingerprint and then said it failed”, which is usually a ceremony that completed at the device and was refused by the server — an expired challenge, a clock problem, or a session that had already consumed it. Your internal reason code answers it immediately, which is a good argument for surfacing that code to your support tooling even though it never reaches the user.
The third is a report of an unfamiliar dialog, which is generally a third-party credential manager. Nothing is wrong, and the useful response is to confirm the credential works rather than to try to reproduce an interface you do not control.
For all three, the thing that shortens the conversation is a settings page the user can read. Asking somebody to look at their passkey list and say which entries they recognise turns an abstract problem into a concrete one, and it frequently resolves the issue without any further investigation — which is one more reason the management surface repays the effort spent on it.
Related
- Frontend UX and Conditional Mediation — the parent topic area and the client-side surface
- Passkeys on iOS and Safari — the platform-specific behaviour in detail
- Passkeys on Android and Windows Hello — the other two major platforms
- Feature-Detecting Passkey and Conditional Mediation Support — the runtime probes this depends on
- Conditional Mediation Browser Support Matrix — why runtime beats published tables