DEV Community

Cover image for Protect your React Native application using Cloudflare Turnstile.
Vlad R
Vlad R

Posted on

Protect your React Native application using Cloudflare Turnstile.

Quick overview:

Turnstile is Cloudflare’s smart CAPTCHA alternative. It can be embedded into any website without sending traffic through Cloudflare and works without showing visitors a CAPTCHA.

Turnstile has a great documentation. Here is the link.

Here is how it looks like:

Cloudflare turnstile widget

How it works:

how turnstile works under the hood

Turnstile is a front-end widget that creates a token which is cryptographically secured. However, the customer cannot check the validity of the token on their end. To ensure that a token is not forged by an attacker or has not been consumed yet, the customer needs to check the validity of a token using Cloudflare’s siteverify API. A Turnstile token is valid for 300 seconds. It refreshes automatically.

Widget types:

There are three types of Turnstile widget:

  • A non-intrusive interactive challenge (such as clicking a button), if the visitor is a suspected bot.
  • A non-interactive challenge.
  • An invisible challenge to the browser.

cloudflare widget types

Pricing:

Turnstile is currently in open beta and available as a free tool, but there are still some limitations.

React Native integration:

Turnstile doesn’t offer an easy and official way to embed Turnstile into a React Native application. The only one way to render the widget in RN app is by using WebView component.

We also gonna use the invisible type of widget(set widget type in the CF dashboard). Which means our users won’t see any widget at all and we won’t have to try to style an iframe inside of an iframe in order to fit the widget into our design.

const Turnstile = () => {
  const dispatch = useDispatch();

  const handleMessage = (event) => {
    //  Now we can add this token to any request header.
    //  Where backend will verify the token using Cloudflare API.
    const token = event.nativeEvent.data;
    dispatch(setTurnstileToken(token));
  };

  return (
    <View>
      <WebView
        originWhitelist={['*']}
        onMessage={handleMessage}
        source={{
          baseUrl: '{your base url}',
          html: `
                <!DOCTYPE html>
                <html>
                  <head>
                   <script src="https://challenges.cloudflare.com/turnstile/v0/api.js?onload=_turnstileCb" async defer></script>
                  </head>
                  <body>
                     <div id="myWidget"></div>
                     <script>
                        // This function is called when the Turnstile script is loaded and ready to be used.
                        // The function name matches the "onload=..." parameter.
                        function _turnstileCb() {
                            turnstile.render('#myWidget', {
                              sitekey: '{your siteKey}',
                              callback: (token) => {
                                // Success callback, which sets the token into a separate store slice.
                                window.ReactNativeWebView.postMessage(token);
                              },
                            });

                        }
                     </script>
                  </body>
                </html>
            `,
        }}
      />
    </View>
  );
};
Enter fullscreen mode Exit fullscreen mode

Don’t forget to change baseUrl and siteKey props.

Then import the component above to the App component.

const App = () => {
  return (
     ...
     <Turnstile />
  )
}
Enter fullscreen mode Exit fullscreen mode

That’s about it. Easy. Hope sometimes soon we’ll be able to use other types of the widget.


Photo by José Ramos

Top comments (0)