Protect your React Native application using Cloudflare Turnstile.
Tags: reactnative, cloud, security, typescript
Published: 2023-02-21 11:48:04

### 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](https://developers.cloudflare.com/turnstile/).

Here is how it looks like:

![Cloudflare turnstile widget](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nskn96xraflznefeyvcr.png)

### How it works:

![how turnstile works under the hood](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l2v70l9bdwyviiuy7w32.png)

> 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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mug0vov544na8gnibj28.png)

### Pricing:

Turnstile is currently in open beta and available as a free tool, but there are still some [limitations](https://developers.cloudflare.com/turnstile/#availability).  
 
  

### 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](https://github.com/react-native-webview/react-native-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.

```jsx
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>
  );
};
```

Don’t forget to change `baseUrl` and `siteKey` props.

Then import the component above to the App component.

```jsx
const App = () => {
  return (
     ...
     <Turnstile />
  )
}
```

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

---
> Photo by [José Ramos](https://unsplash.com/photos/BWCgQw25XUE)