> For the complete documentation index, see [llms.txt](https://intercode.gitbook.io/intercode-saas-kit/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://intercode.gitbook.io/intercode-saas-kit/features/captcha.md).

# Captcha

To begin working with Google reCAPTCHA you should register your website on official google captcha website:

{% embed url="<https://www.google.com/recaptcha>" %}

After you registered you will see dashboard where you will be able to see analytics about how many users passed/failed captcha or how many users passes captcha without check. To get .env variables and setup other settings click on following icon:

<figure><img src="/files/t8b9pUsXtLdOe9AtH49b" alt=""><figcaption></figcaption></figure>

On settings page you will see next sections:

* reCAPTCHA keys - open that sections to see your .env variables (`SITE_KEY` and `SECRET_KEY`)
* Domains - add your production, stage domens here and do not forget to add localhost for correct captcha work while development
* Owners - add emails which you want grant access to captcha admin panel
* Security Preference - set up captcha diffuculty

<figure><img src="/files/X0nvD5WjS3JARNEARENQ" alt=""><figcaption></figcaption></figure>

After that you should set up **.env** variables to **ui** and **api**. In **api/.env** add variable `CAPTCHA_SECRET_TOKEN` with value of generated previously `SECRET KEY` (do the same on production deploy). In **ui** folder for development add `REACT_APP_CAPTCHA_SECRET` to **.env.develpment** with value of your `SITE_KEY`.

For correct build on frontend you should also add `REACT_APP_CAPTCHA_SECRET` to **.github/ui.yml** `builds-args` and for production add that argument to Dockerfile\_ui with following syntax:

```dockerfile
ARG REACT_APP_CAPTCHA_SECRET
ENV REACT_APP_CAPTCHA_SECRET=$REACT_APP_CAPTCHA_SECRET
RUN echo $REACT_APP_CAPTCHA_SECRET
```

To add reCAPTCHA on frontend you need to install `react-google-recaptcha`. After that use ReCAPTCHA component on your page:

```javascript
                <ReCAPTCHA
                    sitekey={constants.CAPTCHA_SECRET}
                    ref={captchaRef}
                    onChange={handleCaptchaChange}
                />
```

For correct usage pass required prop sitekey with value of your `REACT_APP_CAPTCHA_SECRET` variable. Moreover for correct reseting reCAPTCHA create reference with `useRef()` hook. You will be able to reset your reCAPTCHA in case of error or else cases in the following way:

```javascript
captchaRef.current.reset();
```

The `handleCaptchaChange` function will execute when the user completes the captcha, setting the generated captcha token in the page state. This token will then be passed to the API in the sign-in request. Code example:

```javascript
    const handleCaptchaChange = token => {
        setCaptchaToken(token);
    };
```

On backend you should add call to google api which will check if token is valid, you can write this check in controller or in service. Make a post request to google api on following URL:

```typescript
`https://www.google.com/recaptcha/api/siteverify?secret=${constants.CAPTCHA_SECRET_TOKEN}&response=${captchaToken}`
```

You should pass your secret key and token to check in search params. Then add check if `response.data.success` is true. If it is **false** throw `BadRequestException`. Full code example:

```typescript
@Post('sign-in')
    async authSignIn(
        @Body('credentials') credentials: AuthPayload,
        @Body('captchaToken') captchaToken
    ): Promise<UserTokens> {
        const response = await axios.post(
            `https://www.google.com/recaptcha/api/siteverify?secret=${constants.CAPTCHA_SECRET_TOKEN}&response=${captchaToken}`
        );

        if (!response.data.success) {
            throw new HttpException(
                {
                    message: 'Error',
                    description: 'Captcha token is not valid',
                    code: 'INVALID_CAPTCHA',
                },
                HttpStatus.BAD_REQUEST
            );
        }

        return await this.authService.emailPwdAuth(credentials);
    }
```

{% hint style="danger" %}
Token is valid only once and expires in 2 minutes.
{% endhint %}
