Search code examples
flutterpaypalflutterwebviewpluginwebview-flutter

webview_flutter violates content security policy, any solutions?


Edit: I got to the bottom of the error for PayPal specifically. For some reason this error only occurs when a test card number is used (in sandbox mode), trying a real credit card number makes the error go away. I believe it is due to a new currency selection feature on PayPal which uses a iFrame.

I am using webview_flutter to go through a PayPal checkout page. It used to work but possibly a update on PayPal's side broke it now I get these Content Security Policy errors:

cancelBuffer: slot 1
I/chromium(19561): [INFO:CONSOLE(425)] "Refused to execute inline event handler because it violates the following Content Security Policy directive: "script-src 'nonce-PHXXXXXXXXXXXXXia13HX3l2n4' 'self' https://*.paypal.com https://*.paypalobjects.com 'unsafe-inline' 'unsafe-eval'". Note that 'unsafe-inline' is ignored if either a hash or nonce value is present in the source list.
I/chromium(19561): ", source: https://www.paypal.com/webapps/xoonboarding?token=EC-1G3XXXXXX5C&country.x=CA&locale.x=en_CA&fromSignupLite=true&fallback=1&reason=dW5oYW5XXXXXZ2VuY3k%3D (425)
"Refused to connect to 'https://www.google-analytics.com/collect' because it violates the following Content Security Policy directive: "connect-src 'self' https://*.paypal.com https://*.paypalobjects.com https://*.qualtrics.com".

I've tried different versions of the plugin and different devices, yet I'm met with this error every time. (When I click the checkout button after filling out payment info on PayPal).

My Flutter code:

body: WebView(
          initialUrl: checkoutUrl,
          javascriptMode: JavascriptMode.unrestricted,
          navigationDelegate: (NavigationRequest request) {
            if (request.url.contains(returnURL)) {
              final uri = Uri.parse(request.url);
              final payerID = uri.queryParameters['PayerID'];
              if (payerID != null) {
                services
                    .executePayment(executeUrl, payerID, accessToken)
                    .then((id) {
                  widget.onFinish(id);
                  Navigator.of(context).pop();
                });
              } else {
                Navigator.of(context).pop();
              }
              Navigator.of(context).pop();
            }
            if (request.url.contains(cancelURL)) {
              Navigator.of(context).pop();
            }
            return NavigationDecision.navigate;
          },
        ),

Solution

  • PayPal Checkout can only be used within a Safari View Controller or Chrome Custom Tab: https://developer.paypal.com/docs/api/info-security-guidelines/#secure-applications

    Webviews without an address bar such as WKWebView or Android's Platform Views are not supported

    If your checkout itself operates in a WebView and you need to "pop over" to SFVC/CCT for just the PayPal window, the popup bridge library (either Android or iOS version) can be useful.