AWS Cognito with React reCaptcha v2
Tags: cognito, captcha, serverless, react
Published: 2020-08-25 02:02:49

## AWS Cognito

Cognito is a managed service for user management provided by AWS. Though it seems complete at first, there are a few features that are not available, e.g. captcha, password rotations, password expiry.

They do however provide Lambda triggers on some of their actions. We can extend the functionalities by writing functions that will trigger when Cognito perform such actions, like pre-authentication and post-authentication.

A common requirement when it comes to sign-up/login flows is captcha, which prevents bots from signing up or logging in.

We will be using AWS Amplify for this.

## AWS Lambda

Lambda is a way to run the serverless code on AWS. No provisioning of compute instance is required to run such codes.

## reCaptcha v2

Recaptcha is a captcha service by Google. You do need a Google account to get the site-key and secret-key for reCaptcha to work correctly. We will be using reCaptcha v2.

Upon signing up, take note of the site-key, which will be on the client-side, and the secret-key, which will be on the server-side.

We will be using the react-google-recaptcha for this.

## Installing reCaptcha for React

Install the reCaptcha library to your project dependencies.

```
npm i react-google-recaptcha
```

Render the reCaptcha

```javascript
import ReCAPTCHA from "react-google-recaptcha";
 
function onChange(value) {
  console.log("Captcha value: ", value);
}

<ReCAPTCHA
  sitekey="YOUR SITE KEY HERE"
  onChange={onChange}
/>
```

From this, we can get the reCaptcha token, now we need to send it together with the user credentials to AWS Cognito for verification.

## Passing the token to AWS Cognito

```javascript
import { Auth } from "aws-amplify";

Auth.signIn(username, password, {
        captcha: token,
      }).then...
```

Where username and password are user input credentials, the last parameter is called [clientMetadata](https://aws-amplify.github.io/amplify-js/api/classes/authclass.html#signin) which is not stored by AWS in any way, and only used in the triggers in Lambda.

You can see that we've added the token value with the key "captcha", you will see how we use this value next.

## Creating a Lambda function

Login to your AWS Lambda and create a new function with NodeJS.

![New Lambda Function](https://dev-to-uploads.s3.amazonaws.com/i/ytrq08cr5vvj2wgcvpyt.png)

```javascript
const axios = require("axios");

const config = {
  recaptcha: {
    secretKey: process.env.SECRET_KEY,
  },
};

exports.handler = async(event) => {
  console.log(event);
  if (!event.request.validationData) {
    throw new Error("Missing validation data");
  }
  try {
    const payload = {
      secret: config.recaptcha.secretKey,
      response: event.request.validationData.captcha,
      remoteip: undefined,
    };
    const verifyResponse = await axios({
      method: "post",
      url: "https://www.google.com/recaptcha/api/siteverify",
      params: payload,
    });
    if (verifyResponse.data.success) {
      return event;
    }
    else {
      throw new Error("Recaptcha verification failed");
    }
  }
  catch (error) {
    console.error(error);
    throw error;
  }
};
```

You will also have to add your reCaptcha secret-key into the environment variables in the Lambda page.

![Lambda Env Var](https://dev-to-uploads.s3.amazonaws.com/i/xd44f7wcf9ayn3bxsojw.png)

After adding this code in Lambda, add this Lambda function to your pre-authentication trigger of your AWS Cognito User Pools.

![Cognito Trigger](https://dev-to-uploads.s3.amazonaws.com/i/5sfrk2huo2d5iuniomfn.png)

Now that you have your triggers and functions ready, try a login flow in your application, you'll realise that you'll receive an error 400.

That's because Lambda needs the dependencies for your function, in which this case is Axios.

## Upload your codes

Lambda allows you to zip up your codes with dependencies and upload them. What we'll have to do here is to copy that code above into a .js file, install [Axios](https://www.npmjs.com/package/axios) into node_modules, zip it up and upload.

## Finally!

And you're done! You've just altered the authentication flow of AWS Cognito slightly to include a captcha with Lambda!

There are many ways to make use of the triggers to achieve your needs, explore the other triggers and customise them with Lambda!

Cheers!