Passkeys for app sign-in in 2026: what to build and in what order
How passkeys work across iOS, Android and the web, the domain setup that trips teams up, the sign-in patterns we recommend, and what Apple, Google and the FIDO Alliance added in the last year.

Passkeys stopped being an experiment some time ago. Every major platform can create, sync and use them, the WebAuthn standard behind them became a W3C Recommendation at Level 3 this week, and in the last year Apple, Google and the FIDO Alliance shipped the pieces that were missing: account creation without a password, quiet upgrades for existing users, and a way to move passkeys between password managers.
This report is for product teams deciding how to add passkeys to an app that already has users. It covers what a passkey is, what each platform needs from you, the sign-in patterns we recommend, and what changed between mid-2025 and now.
What a passkey is
A passkey is a FIDO credential: a public/private key pair created for one website or app (the relying party). The private key stays with the user's credential manager, such as iCloud Keychain, Google Password Manager or a third-party manager. Your server stores only the public key. To sign in, the device signs a challenge from your server after the user unlocks it with Face ID, a fingerprint or the device PIN.
Two properties matter for product decisions. Passkeys are bound to your domain, so a look-alike phishing site cannot use them. And there is nothing reusable to leak: a database breach exposes public keys, which are useless to an attacker.
- Synced passkey
- Stored in a credential manager that syncs it across the user's devices, end-to-end encrypted. This is what most consumers get by default, and why losing a phone no longer means losing the account.
- Device-bound passkey
- Never leaves one device or security key. Common in workforce and high-assurance settings.
- WebAuthn
- The W3C browser API for creating and using these credentials. Native platform APIs on iOS and Android use the same model, so one server implementation serves all three.
What each platform needs
| Platform | API | Domain link you must publish |
|---|---|---|
| iOS, iPadOS, macOS | AuthenticationServices: ASAuthorizationPlatformPublicKeyCredentialProvider for creating and asserting passkeys, driven by ASAuthorizationController. | Associated Domains entitlement webcredentials:example.com, plus an apple-app-site-association file on that domain listing your app ID. |
| Android 9 and later | Jetpack Credential Manager (androidx.credentials): CredentialManager.create(context), then createCredential() with a CreatePublicKeyCredentialRequest, or getCredential() with a GetPublicKeyCredentialOption. One bottom sheet covers passkeys, passwords and Sign in with Google. | Digital Asset Links: /.well-known/assetlinks.json with the get_login_creds relation for your package and signing certificate. |
| Web | WebAuthn: navigator.credentials.create() and navigator.credentials.get(). | None beyond serving the site from the relying-party domain. |
The domain link is the step that most often breaks a launch. A passkey is created for a relying-party ID, normally your web domain, and the operating system will only let your app use it if the domain vouches for the app. The two files look like this:
{
"webcredentials": {
"apps": ["ABCDE12345.com.example.app"]
}
}
[{
"relation": [
"delegate_permission/common.handle_all_urls",
"delegate_permission/common.get_login_creds"
],
"target": {
"namespace": "android_app",
"package_name": "com.example.app",
"sha256_cert_fingerprints": ["<SHA-256 of your signing cert>"]
}
}]
Credential Manager replaces the older Android APIs for this job: Google's docs point teams to migrate from legacy Google Sign-In, One Tap, Smart Lock for Passwords and the old FIDO2 API. If your app still uses any of those, budget the migration into the passkey work.
The sign-in patterns we recommend
The technology is the easy part. The product questions are when to offer a passkey, how to make it the obvious choice, and what happens when it is not available.
1. Let autofill offer the passkey
Keep a normal username or email field and let the system suggest a passkey in its autofill UI. On the web this is conditional mediation: mark the field with autocomplete="username webauthn" and start a get() call with mediation: 'conditional' when the page loads. If the user picks a passkey, they are in; if they type an email instead, nothing has been lost.
<input type="text" name="username" autocomplete="username webauthn">
<script type="module">
const caps = await PublicKeyCredential.getClientCapabilities?.();
if (caps?.conditionalGet) {
const credential = await navigator.credentials.get({
publicKey: optionsFromServer, // challenge, rpId, etc.
mediation: 'conditional',
});
// send credential to the server for verification
}
</script>
iOS has the same idea in native code: set the username field's text content type to .username and start the request with performAutoFillAssistedRequests(), so passkeys appear in the QuickType bar. Android's Credential Manager shows its bottom sheet with every credential the user has for your app.
2. Upgrade existing users without a prompt
Most of your users will arrive with a password. The old pattern was a full-screen "Create a passkey?" upsell after sign-in. All three platforms now support a quieter path, often called automatic passkey upgrades or conditional create: right after a successful password sign-in, the app asks for a passkey to be created in the background. If the credential manager allows it, the passkey is saved and the system shows a notification; if not, the call fails silently and no UI appears.
- iOS 18 and later: a registration request with
requestStyle: .conditional. - Android:
isConditional = trueonCreatePublicKeyCredentialRequest. The credential provider, for example Google Password Manager, decides whether to create the passkey and is responsible for telling the user. - Web:
navigator.credentials.create()withmediation: 'conditional', after checkinggetClientCapabilities()forconditionalCreate.
We still offer an explicit "Add a passkey" button in account settings, and a one-time prompt when someone signs in with a passkey from another device, which passkeys.dev suggests detecting through the authenticatorAttachment value cross-platform.
3. Keep a fallback and plan recovery
A passkey-only account is a choice with a cost. People switch ecosystems, use shared tablets, or sign in on a friend's laptop. Until your analytics show otherwise, keep at least one other sign-in path: email magic links, a password, or a federated provider. Account recovery should never be weaker than sign-in; an SMS code that can reset a passkey account undoes most of the phishing protection.
Show users their passkeys in settings with the device or manager that created them, and let them remove one. WebAuthn Level 3 and the native APIs now include signal methods (for example PublicKeyCredential.signalAllAcceptedCredentials() on the web) so your server can tell the credential manager when a passkey was revoked or a user renamed their account, and the stale entry stops appearing.
What changed in 2025 and 2026
| Change | Who | What it means for your app |
|---|---|---|
| Account creation API | Apple, iOS 26 and the other 26 releases | ASAuthorizationAccountCreationProvider lets a new user sign up with a passkey in one system sheet that also returns their email or phone number and optionally a name. No password is ever created. |
| Signal APIs | Apple, browsers (WebAuthn Level 3) | ASCredentialUpdater on Apple platforms and PublicKeyCredential.signal* methods on the web keep credential managers in sync with your server: renamed accounts, revoked passkeys, passwords no longer needed. |
| Passkey import and export | FIDO Alliance, Apple | FIDO's Credential Exchange Protocol and Format (CXP and CXF) describe a secure, user-approved transfer of passkeys between credential managers. Apple's 26 releases add import and export between credential manager apps using a schema developed with the FIDO Alliance. Apps and websites need no changes; users stop being locked into one manager. |
| Passkey endpoints well-known URL | W3C draft, credential managers | A JSON file at /.well-known/passkey-endpoints with enroll and manage URLs lets password managers deep-link users to your passkey settings. Cheap to add. |
| Restore Credentials | Google, Android | A restore key, created silently after sign-in and carried over by backup or device-to-device transfer, signs the user into your app on a new Android phone. One account per app; it complements passkeys rather than replacing them. |
| WebAuthn Level 3 Recommendation | W3C, August 2026 | The spec behind conditional create, client capabilities and the signal methods is now a stable Recommendation. |
Where we would start
- Publish both domain files first
apple-app-site-associationwithwebcredentialsandassetlinks.jsonwithget_login_creds, for every build variant. Test on a real device before writing UI. - Use one relying-party ID for app and webUsually your main domain, so a passkey made on the website works in the app and the other way round.
- Add passkey sign-in through autofillConditional mediation on the web, autofill-assisted requests on iOS, Credential Manager on Android.
- Turn on automatic upgrades after password sign-inIt is the fastest way to move an existing user base without nagging anyone.
- Keep a fallback and a recovery path as strong as sign-inDo not let SMS reset a passkey account.
- Show and manage passkeys in settingsList them, let users delete them, and use the signal APIs so managers stay in sync.
- Add the passkey endpoints fileThirty minutes of work, and password managers can send users straight to your setup page.
Sources
- Passkeys · FIDO Alliance
- Bootstrapping an account on a device · passkeys.dev
- What's new in passkeys (WWDC25) · Apple Developer
- Streamline sign-in with passkey upgrades and credential managers (WWDC24) · Apple Developer
- Create a passkey · Android Developers
- Credential Manager prerequisites · Android Developers
- Restore Credentials · Android Developers
- Web Authentication: An API for accessing Public Key Credentials, Level 3 · W3C


