This article explains how to implement passkeys in native iOS / Android apps. You learn when to use a native and when to use WebView (+ type) implementation.

Vincent
Created: October 9, 2023
Updated: November 14, 2025

Passkeys Series: Native Apps
60-page Enterprise Passkey Whitepaper:
Learn how leaders get +80% passkey adoption. Trusted by Rakuten, Klarna & Oracle
| Approach | Adoption | Create Passkeys | Use Passkeys | Manage Passkeys | Technical Complexity | OAuth Support |
|---|---|---|---|---|---|---|
| Native Implementation | 🟢🟢🟢 | High adoption, best UX, seamless biometric | Instant, silent authentication | Full native control | Medium-High | Requires separate flow |
| System WebView | 🟢🟢 | Good adoption, browser-like experience | Standard browser UX, shared keychain | Browser-based management | Low | Excellent |
| Embedded WebView | 🟢 | Lower adoption, requires more setup | Native support iOS & Android (WebKit 1.12.1+), no Conditional UI | Limited control | Medium-High | N/A |
Note: System and Embedded WebView are often combined where System WebView handles login (with automatic credential sharing), then Embedded WebView renders passkey management in settings.
Key Decision Factors:
Modern mobile platforms provide three distinct approaches to integrate passkeys into your native app, each with different trade-offs for user experience, technical complexity and OAuth compatibility:
Native Implementation: Build passkey flows directly into your app using platform APIs (iOS AuthenticationServices, Android Credential Manager). Provides the best user experience with seamless biometric authentication, but requires medium to high technical implementation effort.
System WebView: Use the platform's browser component (iOS ASWebAuthenticationSession / SFSafariViewController, Android Chrome Custom Tabs) to handle authentication. Excellent for OAuth-based login flows and shares credentials with the system browser.
Embedded WebView: Embed a customizable web view (iOS WKWebView, Android WebView) within your app to reuse web authentication with a native app skeleton. Provides a native-like appearance without URL bars and full control over the web view UI. Requires additional setup including permissions and entitlements (iOS), and WebView configuration with AndroidX WebKit 1.12.1+ (Android) to enable passkey functionality.
The right choice depends on your app's authentication architecture, whether you use OAuth providers, how much control you need over the UI and whether you're building native-first or reusing web components.
A native passkey implementation provides the optimal user experience, with authentication flows built directly into your app's UI using platform-specific APIs. Users benefit from platform-native dialogs, seamless biometric verification and the fastest possible login times.
When to choose Native Implementation:
preferImmediatelyAvailableCredentials to
automatically display passkey overlay
when passkeys are available, providing the fastest login experience without requiring
identifier entryKey Advantage: preferImmediatelyAvailableCredentials()
Native implementations can leverage preferImmediatelyAvailableCredentials() to create an
automatic passkey overlay
that appears immediately on app start when passkeys are available. This usernameless flow
provides the fastest possible login experience-users see their passkeys instantly without
entering an identifier first. This capability is exclusive to native implementations
and not available in WebView variants.
While WebView implementations can use Conditional UI (passkey suggestions in input fields), native's automatic overlay provides superior UX with higher passkey usage rates since authentication begins immediately upon app launch.
Technical Requirements Overview:
Native passkey integration requires cryptographic trust between your app and web domain. Without it, the OS will reject all WebAuthn operations. Key requirements:
/.well-known/The major benefit: passkeys created on your website work seamlessly in your app and vice versa.
Implementing passkeys natively on iOS involves Apple's AuthenticationServices framework, which provides an API for WebAuthn operations:
Key Components:
ASAuthorizationController: Manages the authentication flowASAuthorizationPlatformPublicKeyCredentialProvider: Creates passkey requestsDevelopment Tips
?mode=developer to your AASA URL to force fresh fetchesAndroids native passkey implementation uses the Credential Manager API (or the older FIDO2 API for backward compatibility):
Key Components:
CredentialManager: Central API for all credential operationsCreatePublicKeyCredentialRequest: For passkey registrationGetCredentialRequest: For passkey authenticationNote: Android currently lacks iOS's Conditional UI keyboard suggestions in native apps (though Conditional UI works in web apps)
Implementing passkeys natively has important challenges and lessons learned: Integrating at the OS level can surface issues across different devices and OS versions.
While you can implement passkeys using raw platform APIs, purpose-built SDKs significantly accelerate development by handling WebAuthn complexity, edge cases and providing built-in telemetry. SDKs also offer mockable interfaces for unit testing (crucial since you can't test biometrics in simulators).
Recommendation: For native implementations, we recommend using the Corbado SDKs (iOS Swift Passkey SDK, Android Kotlin Passkey SDK) which handle the numerous edge cases discovered through production deployments, provide additional telemetry and testing.
Igor Gjorgjioski
Head of Digital Channels & Platform Enablement, VicRoads
Corbado proved to be a trusted partner. Their hands-on, 24/7 support and on-site assistance enabled a seamless integration into VicRoads' complex systems, offering passkeys to 5 million users.
Passkeys that millions adopt, fast. Start with Corbado's Adoption Platform.
Start Free TrialSystem WebViews use the platform's native browser component to handle authentication within your app. Unlike fully native implementations, System WebViews display web content using the actual system browser (Safari on iOS, Chrome on Android), maintaining shared cookies, saved credentials, and the familiar browser security indicators.
When to choose System WebView:
Key Advantages:
Platform Components:
ASWebAuthenticationSession (recommended for auth flows) or
SFSafariViewController (general browsing)Major companies like Google and GitHub adopted this approach for adding passkey login to their mobile apps via WebView overlays on existing web authentication pages. This works well when fully native authentication rebuilds aren't immediately feasible.
iOS provides two primary System WebView components for authentication:
ASWebAuthenticationSession (Recommended for Authentication):
SFSafariViewController (General Browsing):
| Feature | ASWebAuthenticationSession | SFSafariViewController |
|---|---|---|
| Primary Use Case | Authentication flows | General web browsing |
| OAuth/OIDC | Excellent | Good |
| Passkey Support | Yes | Yes |
| Customization | Limited | Minimal |
If your app uses OAuth-based login, ASWebAuthenticationSession is the recommended
choice as it's specifically designed for authentication scenarios and provides the best
balance of security and user experience.
Chrome Custom Tabs (CCT) provide a Chrome-powered authentication experience within your app:
Key Features:
OAuth Integration: Chrome Custom Tabs are the Android equivalent of iOS ASWebAuthenticationSession, providing excellent OAuth support while maintaining access to stored passkeys.
Embedded WebViews provide full control over the web content rendering within your app, allowing direct manipulation of cookies, sessions and navigation without URL bar. However, this control comes with additional technical requirements to enable passkey functionality.
When to choose Embedded WebView:
Important Context:
Many apps use a hybrid approach: System WebView handles the initial OAuth authentication (where passkeys work seamlessly), then switch to Embedded WebView for post-authentication to manage passkeys in the settings. The challenges arises when trying to use passkeys directly within Embedded WebViews.
Technical Requirements:
Embedded WebViews require additional setup compared to System WebViews:
Platform Components:
WKWebViewandroid.webkit.WebViewTrade-offs:
When implementing passkeys via WebViews, understanding the distinction between System WebViews and Embedded WebViews is crucial. The three approaches outlined above (Native Implementation, System WebView, and Embedded WebView) each serve different use cases.
On iOS, you have multiple options for displaying web content in-app:
On Android, the main choices are:
android.webkit.WebView), which is
essentially a mini browser that can be embedded in your activities. It's highly
customizable but runs in your app's process.In the following sections, we'll delve a bit deeper into these WebView types for iOS and Android, and discuss which might be best suited for passkey authentication flows.
Apple's platform provides the three WebView options listed above. Your choice will affect how smoothly passkeys can be used inside the app:
For testing the different WebView behavior in iOS, we recommend the app WebView - WKWebView and UIWebView rendering.
WKWebView is a versatile WebView component for iOS. Developers can embed a WKWebView to render web content with a high degree of control over the UI and behavior. WKWebView uses the same rendering engine as Safari, so it's very performant and supports modern web features. In theory, WKWebView can handle WebAuthn (and thus passkeys) if configured correctly, but note that some advanced browser features might be restricted for security. One thing to watch out for is that WKWebView by default does not share cookies or keychain data with Mobile Safari. Users might have to log in afresh because their WebView session is isolated from Safari's session. Also, because WKWebView content can be fully customized by the app, the user doesn't see an address bar or Safari UI – which is great for branding, but it means the user has fewer cues to verify the page's legitimacy (a concern for anti-phishing). Some apps have even abused WKWebView to inject scripts or alter content (e.g. TikTok was noted to inject tracking JS via their in-app browser), so one must be careful to use WKWebView in a safe, user-trustworthy manner.
SFSafariViewController provides an in-app Safari experience. When you open a URL with SFSafariViewController, it's almost like opening it in the real Safari browser, except the user stays within your app's UI. The advantage for passkeys is significant: because it's essentially Safari, the user's iCloud Keychain and saved passkeys are accessible. Note that cookies are not shared on iOS 11+. This means if the user already has a passkey for your site, Safari can find it and even display the Conditional UI autocomplete for easy login. SFSafariViewController is less customizable (you can't change its toolbar much), but it automatically handles a lot of security and privacy features. The URL bar is shown, complete with the padlock icon for HTTPS, which gives users confidence they're on the correct domain. In general, SFSafariViewController is considered more secure than a raw WKWebView and is simpler to implement (Apple provides it as a drop-in). The main trade-off is you sacrifice some control over the look & feel. For an authentication flow, that's usually acceptable. The priority here is security and ease of login, which SFSafariViewController excels at by using Safari's context.
| WKWebView | SFSafariViewController | |
|---|---|---|
| User experience | - Native feeling: Users might feel that the web content is a native part of the app because developers can customize the look and feel to match the app's design. - Autofill: Autofill with data from Safari is possible | - Seamless: Seamless user experience using the user's Safari settings ensuring consistent web browsing between native app and browser. |
| Developer experience | - Highly customizable: Extensive customization and configuration available - Flexible: Many APIs for interacting with web content | - Medium customizable: Limited customization options, especially compared to WKWebView, - Simple: Simpler to implement compared to WKWebView |
| Performance | - Rather slow: Depending on the implementation and web content, loading speeds can be optimized, but might still be slower compared to SFSafariViewController due to the additional processing of custom features and interactions. | - Rather fast: Typically offers better performance as it leverages the Safari engine, which is optimized for speed and efficiency, providing fast loading times for web pages. |
| Trust and recognition | - URL Display not required: WKWebView often doesn't show the URL, making it harder for users to verify the webpage. Potential for malicious apps to mimic this behavior and phish credentials. | - Browser-like Experience: Renders web pages using Safari, providing a "browser-like" experience. Users can see the URL and access Safari's auto-fill features, potentially instilling more trust due to the familiar interface. |
| Isolation | - Separated: Cookies and sessions are separated from Safari; users won't be automatically logged into a WKWebView. | - Separated: Cookies and sessions are separated from Safari; users won't be automatically logged into SFSafariViewController either. |
| Vulnerabilities | - Secure: Inherently secure due to Apple's app sandboxing, but on behavior and security depend the app's implementation. Potential vulnerabilities if not implemented correctly. | - More Secure: Benefits from Safari's built-in security features, including anti-phishing and malicious website warnings. Generally considered more secure for displaying web content than WKWebView due to these features and user familiarity with Safari. |
| Other | - Features not available: Some browser features (e.g., WebAuthn) may not be fully accessible due to security concerns and WKWebView running in the application context. - JavaScript injection: Some apps, e.g. TikTok inject tracking JavaScript into their in-app WKWebView, or restrict user controller (e.g. Facebook) - Privacy issues: More community feedback regarding privacy | - No JavaScript injection: Does not allow the execution of JavaScript from the app, enhancing security and privacy. Also it does not support JavaScript alerts or confirmations, potentially impacting user experience on certain web pages. - Reader Mode: Provides a reader mode for a clean, easy-to-read version of articles. |
SFAuthenticationSession / ASWebAuthenticationSession – These classes (the latter being the newer Swift-friendly name) are built specifically for login flows like OAuth or OpenID Connect. When you need to authenticate a user via a web page (perhaps to an external IdP), these sessions are the recommended choice on iOS. They are very similar to SFSafariViewController in that they utilize the Safari browser under the hood and share cookies/storage with Safari. The key difference is that SFAuthenticationSession will always prompt the user that the app wants to authenticate using a webpage (for user awareness) and it will automatically use the user's existing Safari session if available.
The benefit is a seamless SSO experience – if the user is already logged in to the provider in Safari, this session can use that cookie to avoid another login. For passkeys, this is important because it means any passkey credential stored in Safari/iCloud Keychain can be used here as well. Apple's official guidance is to use ASWebAuthenticationSession for anything that looks like a login flow. The pros are enhanced privacy (your app never sees the credentials or cookies, Safari handles it) and built-in SSO support. The con is that it's limited to auth flows (you wouldn't use it to just render arbitrary web content in your app). In summary, if you choose a WebView approach on iOS, ASWebAuthenticationSession is typically the best choice for implementing passkeys because it's secure, shares state with Safari and is purpose-built for authentication.
On Android, the WebView decision is between the classic WebView and Chrome Custom Tabs:
For testing the different WebView behavior in Android, we recommend the app WebView vs Chrome Custom Tabs.
Android WebView (android.webkit.WebView) is a component that lets you embed web pages in your activity layout. It's similar to WKWebView in that it gives you full control: you can intercept navigation, inject JavaScript, customize the UI, etc. It also runs within your app's process. Using a WebView for passkeys means your app loads your web login page, and that page can initiate a WebAuthn passkey ceremony. Modern Android WebView does support WebAuthn (provided the device's WebView implementation is up to date via Android System WebView or the Chrome component). One major consideration: by default, an Android WebView does not share cookies or stored credentials with the user's Chrome browser. So any passkey created or used in the WebView might not be known to Chrome, and vice versa. This isolation can be good for security (your app can't read browser cookies), but it might force users to log in again if they've already authenticated in Chrome. Another issue is trust. A plain WebView doesn't show the URL or SSL lock icon, so users have to trust your app completely not to phish them. Google has even forbidden use of WebView for Google OAuth sign-ins due to potential phishing risks. Performance-wise, WebViews are fine, but they can be slower or more memory-intensive than using the user's default browser, especially if loading heavy pages.
Chrome Custom Tabs (CCT) are a hybrid approach. They allow your app to open a Chrome-rendered page that looks like it's part of your app. You can customize the toolbar color, add an app logo, etc., but the content is rendered by Chrome in a separate process. For passkeys, CCTs have several benefits: they share the user's cookies and credentials with Chrome, meaning if the user has a passkey saved via Chrome (Google Password Manager), the Custom Tab can access it. The user will also see the actual URL and security indicators, which builds trust. Performance is often better – Chrome can be "warmed up" in the background for faster loading. And importantly, security is strong: because it's essentially the Chrome app, things like Google Safe Browsing protect the session, and your app cannot inject arbitrary scripts into the page (preventing certain attacks).
The downside is that it requires the user to have Chrome (or a supported browser) installed and up-to-date. Most Android users do, but on some devices in certain regions, this could be an issue. Overall, if you go with an embedded web approach on Android, Chrome Custom Tabs are recommended for passkey flows, as they provide a good balance of integration and security. In fact, they are analogous to iOS's SFSafariViewController/ASWebAuthSession in many ways – leveraging the default browser for auth.
(Aside: Apple's WKWebView vs SFSafariViewController and Android's WebView vs CCT have many parallels. Both Safari VC and Chrome Tabs share browser state and provide better security, whereas WKWebView/Android WebView give more control but isolate the web content. For passkeys, sharing state (cookies, credential stores) is usually desirable so that the passkey can be accessed and created seamlessly.)
| Feature | WebView | Chrome Custom Tab |
|---|---|---|
| User experience | - Flexibility: Provides a rich set of APIs for interacting with web content and managing user interactions, including handling JavaScript dialogs and permission requests. - Consistency: Managing a consistent UX, especially with varied web content, can be challenging. | - Browser Features: Shares features like Data Saver and synchronized AutoComplete across devices. - Back Button: Allows users to easily return to the app with an integrated back button. - Dependency: Relies on Chrome app, which might not be available or updated on all user devices - Redirect to Browser: Certain functionalities might redirect users to the Chrome app, potentially disrupting the user experience. - Partial Custom Tabs: Only a portion of the screen can be used for the Chrome Custom Tab while the rest shows the native app - Side-sheet: In landscape mode and on large screen devices, the Chrome Custom Tab is only displayed on one side of the screen, while the rest of the screen shows the native app |
| Developer experience | - Highly Customizable: Offers extensive customization options/needs. - Interactivity: Provides numerous APIs for interacting with web content and managing user interactions. | - Customizable: Allows customization of toolbar color, action button, bottom toolbar, custom menu items, and in/out animations. - Callback: Delivers a callback to the application upon an external navigation. - Security Features: Provides out-of-the-box features, eliminating the need to manage requests, permission grants, or cookie stores. |
| Performance | - Mediocre Performance: May not offer the same level of performance of Chrome Custom Tabs (CCT) | - Pre-Warming: Includes pre-warming of the Browser in the background and speculative loading of URLs to enhance page load time. - Priority: Prevents apps launching a Custom Tab from being evicted during its use by elevating its importance to the "foreground" level. |
| Trust and recognition | - URL & SSL not Visible: The URL and SSL information are not inherently visible in a WebView. Unless the app developer implements these features, users won't know if they're on the correct website or a phishing one. | - URL & SSL Visible: Uses the actual Chrome browser to render pages. Users can see the URL and SSL certificate (indicating if the connection is secure). This can provide users with confidence that they're not on a phishing site. |
| Isolation | - Runs within the App's Process: If an app has a vulnerability that allows malicious code execution, there's a risk that the WebView could be compromised. However, WebView also receives updates, but its behavior and security can be more dependent on the app using it. - No Cookie / Session Sharing: Doesn't share cookies or sessions with the device's main browser, offering isolation but possibly requiring users to log in again. | - Runs within Chrome's Process: Being part of Chrome, Custom Tabs run in the same process and have the same security updates and features as Chrome. - Shared Cookie Jar and Permissions Model: Ensures users don't have to re-sign into sites or re-grant permissions. - Chrome Settings & Preferences: Utilizes Chrome's settings and preferences. |
| Vulnerabilities | - Callbacks to Steal Credentials: Potential vulnerabilities include that sometimes JavaScript is required which opens the door for other apps to run malicious code, such as registering callbacks that try to intercept usernames and passwords. - Phishing: Additionally, a malicious app could open another web page that mimics the Link flow in a phishing attempt. | - Google Safe Browsing: Employs Google's Safe Browsing to shield both the user and device from hazardous sites. - Secure Browser Decoration: Ensures the user always sees the exact URL they are interacting with and can view the website's certificate information, reducing the risk of phishing. Furthermore, custom tabs do not allow JavaScript injection. |
| Other | - Google banned WebViews for login users into Google accounts |
Regardless of which implementation approach you choose, certain technical requirements must be met to enable passkey functionality. This section provides comprehensive guidance on configuring well-known association files, iOS entitlements, and Android WebView configuration.
Note on Managed Devices: Passkey behavior changes significantly on managed devices where Mobile Device Management (MDM) policies control credential storage. For testing passkeys on managed devices, see Passkeys on Managed iOS & Android Devices.
Native and Embedded WebView flows require association files to establish cryptographic trust between your app and web domain. System WebView (ASWebAuthenticationSession) and Chrome Custom Tabs do not require app-to-site association.
The AASA file establishes the connection between your iOS app and your web domain, enabling passkeys to work across both platforms.
File Location: https://yourdomain.com/.well-known/apple-app-site-association
Configuration Requirements:
/.well-known/apple-app-site-association on your domainapplication/json.well-known pathExample AASA File:
{ "webcredentials": { "apps": ["TEAMID123.com.example.app"] } }
AASA Caching and Testing:
Apple aggressively caches AASA files (up to 24-48 hours) using a CDN, which can frustrate development and testing. To bypass caching during development:
?mode=developer to your associated domain in Xcode⚠️ Important: Do NOT use ?mode=developer in production releases. This parameter is
for development only-using it in production will prevent iOS from properly detecting your
AASA file, breaking passkey functionality.
Validation: Use Apple's AASA Validator to verify your configuration.
Android uses Digital Asset Links to verify the relationship between your app and website.
File Location: https://yourdomain.com/.well-known/assetlinks.json
Configuration Requirements:
/.well-known/assetlinks.json on your domainapplication/jsonExample assetlinks.json File:
[ { "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": [ "AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99" ] } } ]
Validation: Use Google's Digital Asset Links Generator to create and verify your configuration.
iOS apps require proper entitlements to access passkey functionality. The requirements differ slightly based on your implementation approach.
The entitlements file (often named Runner.entitlements in
Flutter apps or YourApp.entitlements in native iOS
projects) defines special permissions and capabilities granted by Apple's system. For
passkeys, this file configures Associated Domains.
File Location: Typically in your Xcode project at ios/Runner/Runner.entitlements
Native Implementation and Embedded WebView require the Associated Domains capability to link your app with your web domain. System WebView (ASWebAuthenticationSession) does not require this as it runs in Safari context.
Setup in Xcode:
webcredentials: prefixExample Configuration:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>com.apple.developer.associated-domains</key> <array> <string>webcredentials:yourdomain.com</string> <string>webcredentials:subdomain.yourdomain.com</string> </array> </dict> </plist>
| Approach | Associated Domains Required | Additional Configuration |
|---|---|---|
| Native Implementation | Yes | Dedicated Implementation |
| System WebView | Not required | Default web setup works |
| Embedded WebView | Yes | Requires AndroidX WebKit 1.12.1+ configuration |
Multiple Domains: If your app needs to work with multiple domains you might need Related Origin Requests (ROR).
Android Embedded WebViews support passkeys through two distinct approaches: the newer WebKit-based approach (Section 5.3.1) and the older JavaScript bridge approach (Section 5.3.2). System WebView (Chrome Custom Tabs) does not require any configuration-credentials work automatically.
Android provides official WebView passkey samples demonstrating both implementation approaches.
Modern WebKit integration with native passkey handling. This approach provides native WebAuthn support without requiring custom bridge code.
Official Sample: Webkit WebView MainActivity
Requirements:
Implementation:
import androidx.webkit.WebSettingsCompat import androidx.webkit.WebViewFeature // Check if Web Authentication is supported if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_AUTHENTICATION)) { // Enable Web Authentication WebSettingsCompat.setWebAuthenticationSupport( webView.settings, WebSettingsCompat.WEB_AUTHENTICATION_SUPPORT_FOR_APP ) // Enable JavaScript webView.settings.javaScriptEnabled = true }
Key Points:
WebViewFeature.WEB_AUTHENTICATION at
runtimemediation:"conditional" (passkey autofill in input
fields) doesn't work in Embedded WebViewVersion Notes:
Before AndroidX WebKit 1.12.0, native WebAuthn support didn't exist in Embedded WebView. This older approach uses a Web-to-Native bridge to handle passkeys for devices without native WebView WebAuthn support.
Official Samples:
When to Use: Supporting older Android versions or devices with legacy WebView implementations.
Teams had to either:
For detailed implementation, see Android's Credential Manager WebView Integration guide. However, we strongly recommend using the native WebKit 1.12.1+ approach for modern apps.
Recommendation: Use native WebAuthn support with AndroidX WebKit 1.12.1+. If unavailable at runtime, fall back to Chrome Custom Tabs which provides excellent passkey support with shared credentials.
When implementing passkeys in native apps, you need to establish trust between your app and web domain(s). This section covers how to handle single domains, multiple related domains (ROR) and how to verify your well-known association files are properly configured.
For apps using a single domain (e.g. kayak.com), you need:
webcredentials:kayak.comRelated Origins (ROR) is a
WebAuthn feature that allows a single set of passkeys to work across multiple related
domains (e.g. kayak.com, kayak.de, kayak.co.uk).
ROR uses the
/.well-known/webauthn endpoint on each site to define
related origins, NOT the AASA or
assetlinks files.
Key Points:
/.well-known/webauthn with the list of
related originsConfiguration Example:
If your app works with kayak.com and kayak.de, both domains must:
Before going live, verify your well-known files are properly configured and accessible. Apple and Google provide CDN-based test URLs to check file availability:
| Domain | Apple AASA Verification | Google Digital Asset Links Verification |
|---|---|---|
| kayak.com | Test AASA file Check if Apple CDN can retrieve your file | Test assetlinks.json Verify Google can access your asset links |
| kayak.de | Test AASA file Check if Apple CDN can retrieve your file | Test assetlinks.json Verify Google can access your asset links |
Using These Test URLs:
?nocache=1 parameter forces fresh retrieval, bypassing CDN cachekayak.com or kayak.de with your own domain(s) in the URL patterns aboveTesting Gotcha: Ensure all domains have properly configured well-known files. A missing or misconfigured file on any domain can break passkey functionality for that domain.
More Information: WebAuthn Relying Party ID in Native Apps
Choosing the right implementation approach depends on your app's authentication architecture, OAuth requirements, and need for session control. Use this decision tree to determine the best path forward.
Start with these key questions:
Does your app use OAuth-based login (OAuth2, OIDC, social login providers)?
ASWebAuthenticationSessionDo you want to reuse web authentication in a native-like shell (no URL bar, full UI control)?
WKWebView + Associated Domains entitlementsWebView + AndroidX WebKit 1.12.1+ configurationAre you building a new native app or have native login screens?
Do you have existing web authentication you want to reuse?
Here's how each approach performs across key dimensions:
| Approach | Create Passkeys | Use Passkeys | Manage Passkeys | Technical Complexity | OAuth Support | Setup Time |
|---|---|---|---|---|---|---|
| Native Implementation | High adoption Seamless biometric, best UX | Instant, silentpreferImmediatelyAvailableCredentials enables automatic overlay on app start | Full native control Integrate with app settings | Medium-High Platform-specific APIs | Requires separate OAuth flow implementation | Weeks to months |
| System WebView | Good adoption Browser-like experience, familiar | Standard browser UX Conditional UI in input fields, shared keychain | Browser-based Users manage via browser | Low Minimal native code | Excellent Purpose-built for OAuth | Days to weeks |
| Embedded WebView | Lower adoption Requires configuration | Native WebAuthn support WebKit 1.12.1+, no Conditional UI | Limited control No native integration | Medium-High WebView config + permissions | Requires configuration | 1-2 weeks |
Dimension Explanations:
Recommended: System WebView
If your app authenticates via OAuth2, OIDC or social login providers (Google, GitHub, Microsoft, etc.), System WebView is the optimal choice:
ASWebAuthenticationSession is purpose-built for OAuth flowsExample: Travel apps like kayak.com and kayak.de use OAuth for authentication. System WebView allows them to maintain their existing OAuth infrastructure while adding passkey support through their web authentication pages.
Recommended: Hybrid Approach
Use System WebView for initial OAuth authentication, then Embedded WebView for post-auth sessions:
When to use: Apps that authenticate via OAuth but then need to display authenticated web content where direct session manipulation is required.
Recommended: Native Implementation
Building from scratch or have native screens? Go fully native:
preferImmediatelyAvailableCredentials to display
automatic passkey overlay on app start -
exclusive to native implementations and providing the highest
conversion ratesFor New Apps: Strongly recommend building native login from day one. Sets you up for optimal UX and avoids future WebView-to-native migrations.
Recommended: Phased Migration
This phased approach allows incremental improvements without disrupting existing users.
| Requirement | Native | System WebView | Embedded WebView |
|---|---|---|---|
| Well-known files (AASA/assetlinks) | Required | Not required | Required |
| iOS Associated Domains | Required | Not required | Required |
| Android WebKit Library | Not applicable | Not required | Required (1.12.1+) |
| Relying Party ID | Must match domain | Must match domain | Must match domain |
See Section 5 for detailed configuration instructions.
Testing passkeys in native apps requires a structured, multi-layered approach. Follow the testing pyramid: unit tests (isolated logic), integration tests (WebAuthn ceremony on simulators/emulators) and system tests (end-to-end on physical devices).
Essential Test Categories:
For comprehensive testing guidance including automation strategies, platform-specific gotchas and a complete pre-flight checklist, see our dedicated guide: Testing Passkey Flows in Native iOS & Android Apps.
Consider prompting users to create passkeys after successful traditional login (password, OAuth). This gradual conversion approach:
Example: After OAuth login via System WebView, show a native prompt: "Enable faster login with Face ID?" If accepted, create passkey through web page loaded in System WebView.
Deciding how to implement passkeys - via Native Implementation, System WebView or Embedded WebView is a crucial design choice that impacts security, user experience, and development complexity. There is no one-size-fits-all answer.
For OAuth-based apps: System WebView (ASWebAuthenticationSession, Chrome Custom Tabs) is the recommended starting point. It provides excellent OAuth support, minimal implementation effort, and automatic credential sharing.
For native-first apps: Go native sooner rather than later. A native passkey login
offers the most seamless UX with exclusive capabilities like
preferImmediatelyAvailableCredentials, which enables
automatic passkey overlay on app start-something
WebView implementations cannot provide. With iOS and Android now providing first-class
support for passkeys, real-world successes demonstrate high adoption. The tooling
(including open-source SDKs and platform libraries) has matured to make native integration
achievable in reasonable time frames. While you must be mindful of device management
policies, cross-device sync, and third-party providers, these challenges can be managed
with careful engineering and testing. The result is an app login that delights users with
its ease and speed while significantly improving security.
For embedded WebView frame requirements: Embedded WebView is commonly used in two real-world scenarios. First, OAuth-based apps often use System WebView for the initial login flow, then switch to Embedded WebView to render passkey management options in settings screens where session control is needed-though some apps simplify this by keeping System WebView for both flows. Second, apps that already embedded their authentication flow in WebView frames before adopting passkeys continue this pattern for consistency. Embedded WebView with native WebAuthn support (AndroidX WebKit 1.12.1+) requires configuration and setup (permissions, entitlements, WebView settings) but no longer needs custom JavaScript bridge code. Note that Conditional UI is not supported in Embedded WebView. Choose this approach when maintaining existing embedded authentication patterns or when you need session/cookie control for post-authentication screens.
Ultimately, passkeys in native apps represent a huge leap forward in both user convenience and security. Whether implemented via Native, System WebView, or Embedded WebView, they eliminate phishing risks and password management burdens for your users. Real-world implementations like VicRoads' native app passkey integration demonstrate that native-first approaches deliver the highest user adoption and satisfaction when properly executed with features like automatic passkey overlays. Following best practices for user-friendly authentication and choosing the implementation approach that matches your app's architecture-native-first for new apps, System WebView for OAuth flows, or Embedded WebView for existing embedded patterns-you can offer passwordless, biometric logins that truly realize the vision of passkeys: simple, safe, and delightful authentication for everyone.
If passkeys aren't working in your native app, check these common issues by implementation approach:
application/json.well-known pathhttps://your-domain.com (not app://)webcredentials:yourdomain.comASWebAuthenticationSession (recommended) or SFSafariViewController?mode=developer during development (remove for production)WebViewFeature.WEB_AUTHENTICATIONsetWebAuthenticationSupport() called with
WEB_AUTHENTICATION_SUPPORT_FOR_APP"NotAllowedError: The request is not allowed by the user agent or the platform in the current context"
setWebAuthenticationSupport() callNo passkey prompt appears
?mode=developer on iOS for testing, verify
WebView typeFor detailed debugging, see our article on Relying Party IDs in native apps.
Corbado Native SDKs:
Platform Documentation:
Validation Tools:
Passkeys Series: Native Apps
Related Articles
WebAuthn Relying Party ID (rpID) & Passkeys: Domains & Native Apps
Vincent - September 21, 2023
WebAuthn Resident Key: Discoverable Credentials as Passkeys
Vincent - September 28, 2023
Tutorial: How to Get Full Flutter Passkey Auth SDK in <1h
Lukas - September 5, 2023
Table of Contents