Bug Report
Capacitor Version
Latest Dependencies:
@capacitor/cli: 8.4.0
@capacitor/core: 8.4.0
@capacitor/android: 8.4.0
@capacitor/ios: 8.4.0
Installed Dependencies:
@capacitor/core: 8.1.0
@capacitor/android: 8.1.0
@capacitor/cli: 8.1.0
@capacitor/ios: 8.1.0
Plugin Version
@capgo/inappbrowser: 8.1.24
context(s)
ManualModel: false
AutoMode: false
CapgoCloud: false
OnPremise: false
Platform(s)
Android only. (iOS is unaffected — the didReceive challenge handler in WKWebViewController.swift falls through to performDefaultHandling for client certificate challenges, so no UI is shown.)
Current Behavior
WebViewDialog.java implements onReceivedClientCertRequest and unconditionally forwards every TLS client certificate request to the OS picker via KeyChain.choosePrivateKeyAlias(activity, ..., null /* alias */). There is no option gating this behavior (Options.java contains no related flag, checked up to 8.6.14).
As a result, any HTTPS server that sends an optional CertificateRequest during the TLS handshake — common with payment gateways (in our case PolCard / Fiserv Poland, ssl.dotpay.pl:443) — makes the Android system dialog "Choose certificate — The app X has requested a certificate..." pop up in the middle of a payment flow.
The impact is device-dependent, which makes it hard to diagnose:
On most devices the user credential store is empty, so users see nothing or a near-empty picker.
On Samsung (One UI) devices the keystore ships pre-populated with system entries (FindMyMobile, AttestationKey_com_wssyncmldm with CN=Fake), so every Samsung user gets a scary certificate dialog listing fake-looking certificates during checkout. Non-technical users abandon the payment at this point.
Selecting "Deny" lets the handshake complete normally (the server's request is optional), which confirms the prompt adds no value here — the connection works without a client certificate.
This is a regression in user-facing behavior vs v7.x, which did not override onReceivedClientCertRequest, so the WebViewClient default applied: the request was silently canceled and the handshake completed without a client certificate.
Expected Behavior
By default, a client certificate request should be canceled silently (pre-8.x behavior and the Android WebViewClient default). Showing the system picker should be opt-in, e.g.:
InAppBrowser.openWebView({
url,
clientCertificate: 'prompt' // default: 'none' (cancel silently)
});
Alternatively, only invoke KeyChain.choosePrivateKeyAlias when the developer explicitly opted in for the given host — the plugin already maintains a clientCertificateIdentities map that could serve as that opt-in.
Code Reproduction
- Create a fresh Capacitor 8 app, install @capgo/inappbrowser, and call:
await InAppBrowser.openWebView({ url: 'https://<test-server>' });
- Point it at any HTTPS server configured with optional client certificate verification, e.g.:
- nginx: ssl_verify_client optional;
- ASP.NET Core Kestrel: ClientCertificateMode.AllowCertificate
- On the device, install any user client certificate (Settings → Security → Encryption & credentials → Install a certificate → VPN and app user certificate), or use a Samsung device which has keystore entries out of the box.
- Open the page — the system certificate picker appears immediately during page load. The same page opened in the same app with plugin v7.x loads silently.
Other Technical Details
npm --version output: 10.9.8
node --version output: v22.22.3
pod --version output (iOS issues only): n/a (Android-only issue)
Additional Context
- Real-world trigger: PolCard / Fiserv Poland payment gateway (ssl.dotpay.pl:443) sends an optional TLS CertificateRequest; our users on Samsung devices get the certificate dialog during rent payments.
- Workaround we currently ship: patch-package replacing the method body with request.cancel().
- Happy to submit a PR adding the opt-in option if you agree on the API shape.
Bug Report
Capacitor Version
Plugin Version
context(s)
Platform(s)
Android only. (iOS is unaffected — the didReceive challenge handler in WKWebViewController.swift falls through to performDefaultHandling for client certificate challenges, so no UI is shown.)
Current Behavior
WebViewDialog.java implements onReceivedClientCertRequest and unconditionally forwards every TLS client certificate request to the OS picker via KeyChain.choosePrivateKeyAlias(activity, ..., null /* alias */). There is no option gating this behavior (Options.java contains no related flag, checked up to 8.6.14).
As a result, any HTTPS server that sends an optional CertificateRequest during the TLS handshake — common with payment gateways (in our case PolCard / Fiserv Poland, ssl.dotpay.pl:443) — makes the Android system dialog "Choose certificate — The app X has requested a certificate..." pop up in the middle of a payment flow.
The impact is device-dependent, which makes it hard to diagnose:
On most devices the user credential store is empty, so users see nothing or a near-empty picker.
On Samsung (One UI) devices the keystore ships pre-populated with system entries (FindMyMobile, AttestationKey_com_wssyncmldm with CN=Fake), so every Samsung user gets a scary certificate dialog listing fake-looking certificates during checkout. Non-technical users abandon the payment at this point.
Selecting "Deny" lets the handshake complete normally (the server's request is optional), which confirms the prompt adds no value here — the connection works without a client certificate.
This is a regression in user-facing behavior vs v7.x, which did not override onReceivedClientCertRequest, so the WebViewClient default applied: the request was silently canceled and the handshake completed without a client certificate.
Expected Behavior
By default, a client certificate request should be canceled silently (pre-8.x behavior and the Android WebViewClient default). Showing the system picker should be opt-in, e.g.:
Alternatively, only invoke KeyChain.choosePrivateKeyAlias when the developer explicitly opted in for the given host — the plugin already maintains a clientCertificateIdentities map that could serve as that opt-in.
Code Reproduction
Other Technical Details
npm --version output: 10.9.8
node --version output: v22.22.3
pod --version output (iOS issues only): n/a (Android-only issue)
Additional Context