Get your free and exclusive +30-page Authentication Analytics Whitepaper

How to Sync Passkeys across Devices & Platforms

Learn how to sync passkeys across iOS, Android, Windows and web apps. Covers iCloud Keychain, Google Password Manager and third-party sync.

Vincent Delitz

Vincent

Created: November 16, 2023

Updated: March 10, 2026

passkeys sharing
PasskeysCheatsheet Icon

Looking for a dev-focused passkey reference? Download our Passkeys Cheat Sheet. Trusted by dev teams at Ally, Stanford CS & more.

Get Cheat Sheet

1. Introduction: how to Sync Passkeys across Devices#

We strongly recommend reading our article on Relying Party IDs before diving deeper into this article, as it helps to understand things better.

One of the biggest advantages of passkeys over traditional WebAuthn credentials is that synced passkeys can be shared across different platforms and devices. This means you can sync passkeys between web apps and native apps, even across different ecosystems like iOS, Android and Windows.

In this comprehensive guide, we cover both the conceptual side - how passkey sync works via iCloud Keychain, Google Password Manager, Microsoft Password Manager and third-party passkey providers - and the practical implementation side using Next.js, Flutter (iOS/Android) and Golang.

We also cover how to transfer passkeys to a new phone, share passkeys from iPhone to Android and what the new Credential Exchange Protocol (CXP) means for passkey portability.

This blog post is for you if you're looking to sync passkeys across devices in your own apps or just want to understand how cross-platform passkey sharing works. If you're only interested in a web app tutorial, please see our guides for popular frameworks (React, Angular, Vue.js, Next.js, Nuxt.js, SvelteKit, PHP Symfony, Node.js, Python Flask, Java Spring), and for a Flutter tutorial, see here. The real challenge is not the code itself but the setup and configuration.

As a practical example, we use the setup of the Corbado developer panel with a web app and native Flutter apps for iOS and Android.

Sharing passkeys in this blog post should not be mistaken with sharing passkeys within e.g. an Apple account to let other family members access your passkeys. For more details on this process, please check our guide on sharing passkeys between Apple devices.

You can find the completed code for the Flutter app in this GitHub repository.

2. Prerequisites: syncing Passkeys across Devices#

Before we dive into setting up our applications, let's ensure we're all on the same page regarding the foundational knowledge and tools needed to follow the tutorial.

2.1 Knowledge Base for cross-platform Passkey Sharing#

Native & Web Apps Basics: A fundamental understanding of native app development and general web app architecture is crucial for implementing cross-platform passkey sharing.

Passkeys & WebAuthn: A solid understanding of passkeys and WebAuthn is essential since we'll be delving into advanced configurations and setups for passkey synchronization. Ensure you're familiar with the basic processes and functionalities of passkeys and WebAuthn to smoothly navigate through the tutorial. In case you need some refreshments on certain topics, please have a look at our other detailed blog posts:

2.2 Tools and technologies#

Flutter:

We'll be using Flutter for developing the native app. Ensure you have it installed and are familiar with its basic functionalities. In Flutter, we use the corbado_auth package, which internally uses the passkeys package.

Next.js:

The application will be built using Next.js. Next.js provides a full-stack framework that allows us to handle both client-side and server-side logic efficiently. Familiarity with Next.js, especially in the context of full-stack development, will be beneficial.

Corbado UI Components:

In the Next.js application, we'll implement the Corbado React UI components, which comes with a lot of passkey features out-of-the-box simplifying the integration process and ensuring seamless interaction with the backend. These components are part of Corbado UI components.

Slack Icon

Become part of our Passkeys Community for updates & support.

Join

3. Architecture for cross-platform Passkey Sharing App#

Embarking on a journey to implement passkey sharing between web and native applications necessitates a thorough understanding of the underlying architecture. Let's delve into the core concepts and architectural components that will be the backbone of our setup.

3.1 System architecture#

Let's first have a look at the different components that we have in our setup:

3.1.1 Golang backend#

Application Server:

The application server is written in Golang (while any other programming language or framework would have worked as well). It manages all the incoming requests and takes care of all the business logic. In our setup, it is accessible via https://auth.corbado.com.

WebAuthn Server:

The central part for passkey authentication / WebAuthn is the WebAuthn server (also called the relying party backend), which is responsible for managing authentication requests and enabling cross-platform passkey sharing. A WebAuthn server can be implemented either as an in-process library/SDK integrated into the application server, or as a separate hosted service (e.g. a managed identity provider). In our example, we use an integrated library approach. Read this blog post to understand more about WebAuthn server implementations. The WebAuthn server is not directly reachable but only via the application server.

Database:

The database is used to store information about the users and passkeys. In our example, we're using MySQL (any other database could have worked as well). The database is not publicly reachable.

3.1.2 Next.js frontend#

Next.js Application:

We use Next.js as our frontend framework, which provides a robust and efficient way to build the user interface. You can access the Next.js application at https://app.corbado.com. You can also take a look into our Nextjs Docs

Corbado Component:

In the web app, we'll be integrating Corbado's React Auth components. There are also Javascript-based components that can be used.

3.1.3 Flutter (iOS & Android) native App#

A straightforward Flutter app is utilized. The Flutter app implements the corbado_auth package (and thus the passkeys package), which facilitates communication with the backend. The package name for the Flutter (iOS & Android) native app is com.corbado.developerpanel.app. For a more detailed documentation please check our Flutter Docs

3.2 Passkey Sharing implications#

3.2.1 Unified Relying Party ID to enable cross-platform Passkey Sharing#

The WebAuthn server, which manages the public keys, is the same for the web and native application. This ensures that the authentication data is consistently available across the two platforms, facilitating seamless passkey sharing and authentication.

Therefore, the Relying Party ID (rpID) needs to be the same for passkeys created either in the web or native app to enable proper passkey synchronization.

The Relying Party ID (rpID) we define in our example is set to corbado.com. To help you find out the suitable Relying Party ID (rpID) for your case, please have a look into our detailed guide here.

The apple-app-site-association file for iOS apps and the assetlinks.json file for Android apps are pivotal in establishing and verifying the relationship between the web and native applications. The files are hosted on our server at

They ensure that a created passkey on either of the two applications can be used on the other one. Its important that server address (https://corbado.com) where the files are stored is the same like the Relying Party ID (corbado.com).

Let's have a look on the content of these two files:

apple-app-site-association:

{ "appclips": { "apps": [] }, "applinks": { "details": [ { "appID": "T9A667JL6T.com.corbado.developerpanel.app", "paths": ["*"] } ] }, "webcredentials": { "apps": ["T9A667JL6T.com.corbado.developerpanel.app"] } }

Currently, there are two entitlements set up: applinks and webcredentials.

applinks is not necessarily needed for passkeys but still set for better UX. It allows to directly open suitable links for the Corbado developer panel in the Flutter native app.

webcredentials is the important one that must be set for passkey synchronization to work properly. As the apple-app-site-association file is hosted at the location of the Relying Party ID server (here at https://corbado.com with the Relying Party ID corbado.com) and downloaded during the app install, the native app is associated to the Relying Party ID.

The value stored in here (the same value as the appID in the applinks entitlement) consists of two elements. The first part is the Application Identifier Prefix (here: T9A667JL6T) and your Bundle Identifier (here: com.corbado.developerpanel.app). The Application Identifier Prefix can be obtained by going to your Apple Developer Certificates, Identifier & Profiles associated with your Apple Developer account.

Note: When creating your Bundle Identifier, make sure that the Associated Domains capability is enabled:

assetlinks.json

[ { "relation": [ "delegate_permission/common.handle_all_urls", "delegate_permission/common.get_login_creds" ], "target": { "namespace": "android_app", "package_name": "com.corbado.developerpanel.app", "sha256_cert_fingerprints": [ "8B:BF:39:60:61:89:30:A4:45:F3:D7:09:1E:7B:1B:05:0F:8A:FD:AF:24:EB:F1:EB:2E:3D:13:88:09:FC:79:59", "AC:B4:93:5D:FC:31:FB:EF:2D:5C:F1:CF:31:E9:B6:8A:1E:7E:F9:0E:FF:23:E5:43:AE:41:44:EF:33:E3:FD:F3", "54:4C:94:2C:E9:2F:6A:C1:7D:56:C2:5D:DB:D6:5E:71:32:A4:0D:62:7E:3E:F2:E4:09:A8:18:9F:D0:63:A8:FB" ] } }, { "relation": [ "delegate_permission/common.handle_all_urls", "delegate_permission/common.get_login_creds" ], "target": { "namespace": "web", "sha256_cert_fingerprints": null, "site": "https://auth.corbado.com" } } ]

As you can see, there are two entries set to associate the web app and the native app.

The first entry is for the target with namespace android_app (our Flutter native app), while the second one is for the target with namespace web (our Next.js web app). Both entries contain each the same two required relations delegate_permission/common.handle_all_urls and delegate_permission/common.get_login_creds. Moreover, the native app entry contains the used package name (here: com.corbado.developerpanel.name) and the SHA-256 signing certificate fingerprint (here e.g.: 8B:BF:39:60:61:89:30:A4:45:F3:D7:09:1E:7B: 1B:05:0F:8A:FD:AF:24:EB:F1:EB:2E:3D:13:88:09:FC:79:59), while the web app contains the URL to the backend's host (here https://auth.corbado.com).

Often generating or extracting the SHA-256 signing certificate causes issues or is confusing. Please have a look at this blog post, where we help you in great detail to get your right values.

Understanding this architecture and its passkey implications lays the foundation to the setup and configuration of our web and native application.

4. Setting up the Next.js Web App#

Now, we have a look on the practical implementation of the Next.js web application. Let's see how the web application can be quickly setup by using the Corbado React package, which saves a lot of development time, as it comes with intelligent passkey management, device detection and passkey UI / UX out-of-the-box. Besides that, we're also using Corbado's session management to have a simple, secure and efficient session management as well.

4.1 Initialization & integration of the Next.js Web App#

4.1.1 Simplified setup with the Corbado React Package#

While we won't delve deep into the detailed setup of the web application in this guide, our other guides provide a comprehensive walkthrough for a basic setup. For our Corbado developer panel example, please have a look at this Next.js passkeys guide with our React package and into our Nextjs passkeys docs. We encourage you to explore it for a thorough understanding of the initial steps.

One of the most crucial steps in the Next.js passkeys guide is defining the Relying Party ID. You can do this in the Corbado developer panel. In there, we set the Relying Party ID for our web app (and thus also for our native app) to corbado.com.

4.1.2 Embedded Auth Component location is important#

The auth component itself can be embedded at any location of the web app. We decided to host our developer panel on the subdomain app.corbado.com. This domain also embeds the Corbado auth component as we wanted to allow our users a sign-up and login from here. As outlined in our Relying Party ID guide, adding the auth component to a subdomain (app.corbado.com) of the Relying Party ID (corbado.com) is fine (but not the other way around).

Additionally, and more as a side note, we also embedded the auth component on our external website www.corbado.com, which is also fine as it still matches the Relying Party ID (corbado.com), because subdomains can access the passkeys of the corresponding root domains. Please take a look at this detailed blog post to better understand the domain matching of the Relying Party ID.

4.2 Passkey Authentication Flow in the Next.js web App#

After we followed the guide above and deployed our application accordingly (for details regarding the go live of a web app, see also our go live guide), we are ready to try the passkey authentication process on our web application. In the following, we explain what happens in the background and which checks are being passed.

Our test device is a MacBook with activated Apple iCloud Keychain where we stored the passkeys in. This allows us to later also used them on an iPhone that is synced in the same Apple iCloud Keychain.

  1. Go to our web app (app.corbado.com), open the sign-up page of the web component to create a new account and provide a name and email address. Then, click on Sign up with 1 click for free.

  1. In the appearing passkey popup create a new passkey and account by authenticating via Touch ID on your MacBook.

  1. Youve successfully created a passkey that is synced in the Apple iCloud Keychain and an account at the web app. Please confirm the new account by clicking on the email magic link sent to your inbox

In this section, weve laid the groundwork for the web application and showed how to create a passkey for the web app. With the Relying Party ID accurately defined and a basic understanding of the authentication flow, were now ready to explore the configuration of the Flutter application in the next section.

Demo Icon

Want to try passkeys yourself in a passkeys demo?

Try Passkeys

5. Setting up the Flutter Native App#

Lets have a deeper look now into the setup of the Flutter application. For speeding up the passkeys implementation process in Flutter, we make use of the corbado_auth package (internally it uses the passkeys package) that comes with all the required settings for passkey authentication on iOS and Android and has basic other authentication SDK features like session management.

5.1 Initialization & integration of the Flutter native App#

Simplified Setup with the corbado_auth package:

While we wont delve deep into the detailed setup of the Flutter app in this guide, this Flutter guide and our Flutter documentation provide a comprehensive walkthrough for a basic setup. We encourage you to explore it for a thorough understanding of the initial steps.

See our full GitHub repository here for details.

5.2 Passkey Authentication Flow in the Flutter native App#

To make things easily reproducible for you, we published a simple Corbado developer panel app into the App Store and Play Store. Please download the corresponding app for your platform.

In the following, we describe the process of using the passkey created before on our MacBook and using it for our login in the iOS app. A synchronization of this passkey to the Android app is not possible, as it is synced in the iCloud Keychain and thus Android smartphones wouldn't have access to it. To allow for such a cross-platform passkey synchronization today, you would need a cross-platform synced password manager, like Dashlane or 1Password (which needs to be installed on both devices) or you can alternatively use the cross-platform passkey authentication with QR codes and Bluetooth.

  1. Open the iOS app. As soon as the login screen is displayed, Conditional UI is triggered and you should see a passkey (including your username / email address you used during creation) as autofill suggestion (here for the email address wexeb73750@fgvod.com). This is not the email address / passkey we created before, so we click on the key symbol next to the autofill line:

  1. After clicking on the icon, we are first asked which cloud account we should use to get access to the passkeys. We select iCloud Keychain, as this is the cloud account where we stored the passkey during the creation.

  1. After clicking on the right account, the Face ID authentication immediately starts. Next, we get an overview of all the passkeys that are available for our iCloud account for this relying party ID. We look for the passkey that was created for: saxofok424@visignal.com

  1. After clicking on the desired passkey, we are automatically forwarded to the logged-in part of the iOS app.

Congrats, thats it! Youve successfully managed to create a passkey on one device (MacBook + web app), sync it via iCloud Keychain to another device (iPhone + native iOS app) and use it for authentication. This process would have also worked the other way round.

In case this does not work take a look at our troubleshooting guide. Alternatively, you can look up the existing passkey on iOSvia Settings -> Passwords on your iPhone and search for corbado.com (or whatever Relying Party ID youre looking for). This should show you all available passkeys for corbado.com: example pictures. This approach works on macOS, Windows and Android as well (with slight adjustments in the steps to be done).

macOS: Settings -> Passwords

Android: Settings -> Password Manager

Windows: Settings -> Passkey

6. Analyzing the Passkey Sync process#

In the previous step, we successfully used the passkey for cross-device synchronization between a MacBook and an iPhone. Depending on where you synced the passkey during passkey creation the following scenarios would also have been possible:

Scenario 1: Cross-Platform Passkey Sharing Between Web and Native Apps

iOS: If you create the passkey in the web app, it will be automatically stored in your iCloud Keychain but also locally on your device. When then opening the native app, iOS will try to access the secure enclave with the locally stored passkeys and make use of it for the login process in the native app. This seamless sync passkeys functionality is what makes cross-platform passkey sharing possible.

Android: The process is here very much the same to iOS. The passkey is stored during creation in the Google Password manager (and synced here), but also locally in the device itself. In the login process of the native app, the local passkey is then used to authenticate in the native app.

In case creating a passkey does not work on your iOS or Android device, you probably have not activated the necessary settings for your platform. Please see here for troubleshooting guidance and further help.

Scenario 2: Create passkey in a device that uses passkey-syncable password manager and use it for login on other device with passkey-syncable password manager

Many modern non-OS password managers (e.g. 1Password or Dashlane) have recently been upgraded to also support passkeys meaning that they take the place of Apple iCloud Keychain or Google Password Manager. Therefore, the passkeys are synced in the non-OS password manager and every passkey-ready device that has the non-OS password manager installed gets access to the passkey and can use it for authentication.

Scenario 3: Create passkey on Android device 1 web app and use it for login on Android device 2 native app (same would also be valid with iPhone)

iOS: If you create a passkey on your iPhone 1 and would have a second iPhone 2, the passkey will be accessible from the second iPhone, as long as both devices are synced in the same Apple iCloud Keychain.

Android: The process here again is very much the same compared to iOS. The only difference is that the passkeys are not stored in the iCloud Keychain but instead stored in the Google Password Manager, which is also available on other Android smartphones from the same Google account.

Scenario 4: Create passkey in native / web app on Android / iPhone and use it for login in web app on Windows 11 via QR code & Bluetooth

If you create a passkey on your Android or iPhone (no matter if its within a native app or web app), you can use this for cross-platform authentication (also called hybrid transport), e.g. to use it in a web app running on a Windows 11. When trying to log into the web app on Windows 11, theres the option to display a QR code that you can scan with your Android or iPhone. Using a Bluetooth proximity check and a tunnel under the hood the passkey from the Android / iPhone is used for authentication and you will be logged into the web app on the Windows device. Please read this blog post if you are interested in details on this process.

Substack Icon

Subscribe to our Passkeys Substack for the latest news.

Subscribe

7. Sync Passkeys with Microsoft / Windows#

A major development in passkey sync happened when Microsoft introduced passkey saving and syncing via Microsoft Password Manager in 2024-2025. On Windows 11, passkeys can now be saved to your Microsoft account and synced across all your Windows devices.

7.1 Microsoft Password Manager Passkey Sync#

Windows users can now sync passkeys to their Microsoft account, making them available on any Windows device signed into the same account. This works similarly to how iCloud Keychain syncs passkeys across Apple devices or how Google Password Manager syncs across Android and Chrome.

For a detailed analysis of Microsoft's passkey implementation, see our Microsoft passkeys best practices analysis.

7.2 Third-Party Passkey Manager Support on Windows#

Starting in late 2025, Windows 11 also introduced a plugin model for third-party passkey managers. This means password managers like 1Password or Dashlane can now natively integrate with the Windows passkey system. For more on managing passkeys on Windows and enabling passkeys on Windows, see our dedicated guides.

8. Transfer Passkeys to a new Phone#

One of the most common questions around passkey sync is: what happens to your passkeys when you switch to a new phone? The answer depends on your platform and passkey provider.

8.1 Transfer Passkeys to a new iPhone#

When you set up a new iPhone and sign in with the same Apple Account, all passkeys stored in iCloud Keychain automatically sync to the new device. No manual transfer is needed - as long as iCloud Keychain is enabled, your passkeys are available immediately. For details on managing your Apple passkeys, see our guide on Apple Passwords.

8.2 Transfer Passkeys to a new Android Phone#

Similarly on Android, passkeys stored in Google Password Manager are synced to your Google account. When you sign in on a new Android device with the same Google account, all passkeys become available automatically. Google also supports syncing passkeys to Chrome on Windows and macOS.

8.3 Transfer Passkeys from iPhone to Android#

Transferring passkeys from iPhone to Android (or vice versa) has historically been the biggest challenge with passkey sync. iCloud Keychain passkeys are not directly accessible on Android devices, and Google Password Manager passkeys are not accessible on iPhones.

There are several solutions:

8.4 iCloud Keychain on Android: Can you Access Apple Passkeys?#

A frequent question is whether you can use iCloud Keychain on Android. The short answer is: no, iCloud Keychain is not available on Android. Apple's passkey sync is limited to the Apple ecosystem (iPhone, iPad, Mac). However, with iOS 26 Apple introduced support for exporting passkeys via the Credential Exchange Protocol, which allows users to transfer passkeys out of iCloud Keychain to other platforms for the first time.

If you need passkeys accessible on both iOS and Android today, the best approach is using a cross-platform passkey provider like 1Password or Dashlane.

Enterprise Icon

Get free passkey whitepaper for enterprises.

Get for free

9. Passkey Portability: iOS 26 and the Credential Exchange Protocol#

A major shift in passkey portability arrived with iOS 26 and the Credential Exchange Protocol (CXP). This FIDO Alliance standard enables secure export and import of passkeys between different credential managers and platforms.

9.1 What CXP Means for Cross-Platform Passkey Sharing#

Before CXP, passkeys were effectively locked into the ecosystem where they were created. iCloud Keychain passkeys stayed in Apple's ecosystem, Google Password Manager passkeys stayed in Google's ecosystem. CXP changes this by defining a standardized, encrypted format for transferring passkeys between providers.

For developers implementing passkey authentication, this means users will increasingly expect to be able to move their passkeys freely. Read our detailed guide on CXP and CXF and our coverage of Apple's WWDC25 passkey announcements for more details.

10. Troubleshooting and lessons learned#

We've spent the last months on providing tools and tutorials to make developers lives easier when it comes to passkey implementation in general but especially to passkeys in native apps and sharing them across devices in platforms.

Once you've got everything set up correctly, it's a pretty smooth process from UX view. Coming there might cause some headaches though due to the lack of documentation and references. Therefore, we created a list of common issues that weve encountered in the past to help you avoid these issues.

10.1 Local Testing Issues for the Flutter App (Emulator & Physical Devices)#

Difficulties in testing passkey login on simple devices led us to develop the Flutter package, aiding developers in circumventing these issues. Explore our troubleshooting section for insights and also take a look into our Physical Device configuration docs.

10.2 Defining the right Relying Party ID#

Identifying and accurately setting up the right relying party ID, which this blog post aims to guide through.

10.3 Native vs. WebView implementation of Passkeys in native apps#

Deciding on the implementation method of passkeys in a native app, be it via WebView or natively. Our guide provides detailed guidance on this aspect.

Ben Gould Testimonial

Ben Gould

Head of Engineering

I’ve built hundreds of integrations in my time, including quite a few with identity providers and I’ve never been so impressed with a developer experience as I have been with Corbado.

10,000+ devs trust Corbado & make the Internet safer with passkeys. Got questions? We've written 150+ blog posts on passkeys.

Join Passkeys Community

11. Conclusion#

In this guide we covered how to sync passkeys across devices and platforms - from the conceptual side (how iCloud Keychain, Google Password Manager and Microsoft Password Manager handle passkey sync) to a practical implementation with Next.js, Flutter and Golang.

Key takeaways:

  • Use the same Relying Party ID for web and native apps to enable cross-platform passkey sharing
  • Passkeys transfer automatically when switching to a new phone within the same ecosystem (iCloud Keychain for Apple, Google Password Manager for Android)
  • Cross-ecosystem transfer (iPhone to Android) is now possible via third-party password managers and the new Credential Exchange Protocol (CXP)
  • Microsoft/Windows passkey sync now supports both native and third-party passkey managers

Join our passkeys community for further discussions and subscribe to our passkeys Substack for the latest developments in passkey authentication.

See what's really happening in your passkey rollout.

Start Observing

Share this article


LinkedInTwitterFacebook