CAPTCHA
Use the plugin to add CAPTCHA to your authentication flow.
Overview
This following tutorial shows you how to add CAPTCHA validation to your authentication flows. The guide makes use of the plugins functionality. A new abstraction layer aimed to simplify how you can add new features in your SuperTokens integration.
Before you start
The plugin supports only the React and NodeJS SDKs.
Support for other platforms is under active development.
You can use the plugin with the following CAPTCHA providers:
Make sure to have the appropriate provider keys before starting the tutorial.
The implementation is in early stages and APIs might change. For more information on how plugins work refer to the references page.
Steps
1. Initialize the frontend plugin
1.1 Install the plugin
npm install @supertokens-plugins/captcha-react
1.2 Update your frontend SDK configuration
import SuperTokens from "supertokens-auth-react";
import CaptchaPlugin from "@supertokens-plugins/captcha-react";
SuperTokens.init({
appInfo: {
appName: "...",
apiDomain: "...",
websiteDomain: "...",
},
recipeList: [
// your recipes
],
experimental: {
plugins: [
CaptchaPlugin.init({
type: "reCAPTCHAv3", // or "reCAPTCHAv2" or "turnstile"
captcha: {
sitekey: "your-site-key",
// Additional configuration based on the captcha provider
},
}),
],
},
});
2. Initialize the backend plugin
2.1 Install the plugin
npm install @supertokens-plugins/captcha-nodejs
2.2 Update your backend SDK configuration
import SuperTokens from "supertokens-node";
import CaptchaPlugin from "@supertokens-plugins/captcha-nodejs";
SuperTokens.init({
supertokens: {
connectionURI: "...",
},
appInfo: {
appName: "...",
apiDomain: "...",
},
recipeList: [
// your recipes
],
experimental: {
plugins: [
CaptchaPlugin.init({
type: "reCAPTCHAv3", // or "reCAPTCHAv2" or "turnstile"
captcha: {
secretKey: "your-secret-key",
},
}),
],
},
});
3. Customize the plugin
By default, the plugin performs CAPTCHA validation on the following authentication flows:
| Recipe | Authentication Flow | Forms | Pre-API Hook Action | API Function |
|---|---|---|---|---|
EmailPassword |
User sign in | EmailPasswordSignInForm |
EMAIL_PASSWORD_SIGN_IN |
signInPOST |
EmailPassword |
User registration | EmailPasswordSignUpForm |
EMAIL_PASSWORD_SIGN_UP |
signUpPOST |
EmailPassword |
Password reset request | EmailPasswordResetPasswordEmail |
SEND_RESET_PASSWORD_EMAIL |
generatePasswordResetTokenPOST |
EmailPassword |
Password reset submission | EmailPasswordSubmitNewPassword |
SUBMIT_NEW_PASSWORD |
passwordResetPOST |
Passwordless |
Generate verification code | PasswordlessEmailForm and PasswordlessPhoneForm and PasswordlessEmailOrPhoneForm |
PASSWORDLESS_CREATE_CODE |
createCodePOST |
Passwordless |
Verify code and sign in | PasswordlessUserInputForm |
PASSWORDLESS_CONSUME_CODE |
consumeCodePOST |
To limit which actions require additional validation, pass additional configuration parameters to the frontend and backend setup steps.
Frontend conditional validation
On the frontend create a custom component that conditionally loads the CAPTCHA provider based on the name of the form.
import { forwardRef, useEffect } from "react";
import type { ComponentPropsWithoutRef } from "react";
import SuperTokens from "supertokens-auth-react";
import CaptchaPlugin, { useCaptcha, useCaptchaInputContainer } from "@supertokens-plugins/captcha-react";
type CaptchaInputContainerProps = ComponentPropsWithoutRef<ReturnType<typeof useCaptchaInputContainer>>;
const CaptchaInputContainer = forwardRef<HTMLDivElement, CaptchaInputContainerProps>((props, ref) => {
const { form, ...rest } = props;
const { load, render, containerId } = useCaptcha();
useEffect(() => {
// CAPTCHA applies/renders only for the EmailPasswordSignUpForm
// and the EmailPasswordResetPasswordEmail
if (form === "EmailPasswordSignUpForm" || form === "EmailPasswordResetPasswordEmail") {
void load().then(() => render());
}
}, [form, load, render]);
return (
<div
ref={ref}
id={typeof containerId === "string" ? containerId : undefined}
className="CAPTCHA-container"
{...rest}
/>
);
});
SuperTokens.init({
appInfo: {
appName: "...",
apiDomain: "...",
websiteDomain: "...",
},
recipeList: [
// your recipes
],
experimental: {
plugins: [
CaptchaPlugin.init({
type: "reCAPTCHAv3", // or "reCAPTCHAv2" or "turnstile"
captcha: {
sitekey: "your-site-key",
},
InputContainer: CaptchaInputContainer,
}),
],
},
});
Backend conditional validation
On the backend pass a custom validation function that tells the plugin which actions should require extra validation.
import SuperTokens from "supertokens-node";
import CaptchaPlugin, { SuperTokensPluginCaptchaConfig } from "@supertokens-plugins/captcha-nodejs";
const shouldValidate: NonNullable<SuperTokensPluginCaptchaConfig["shouldValidate"]> = (api, input) => {
// Only require CAPTCHA for sign up
if (api === "signUpPOST") {
return true;
}
// Check request headers for suspicious activity
if (api === "signInPOST") {
const userAgent = input.options.req.getHeaderValue("user-agent");
return !userAgent || userAgent.includes("bot");
}
return false;
};
SuperTokens.init({
supertokens: {
connectionURI: "...",
},
appInfo: {
appName: "...",
apiDomain: "...",
},
recipeList: [
// your recipes
],
experimental: {
plugins: [
CaptchaPlugin.init({
type: "reCAPTCHAv3", // or "reCAPTCHAv2" or "turnstile"
captcha: {
secretKey: "your-secret-key",
},
shouldValidate,
}),
],
},
});
Next steps
Besides CAPTCHA validation you can also look into the Attack Protection Suite feature which provides prevention against suspicious authentication attempts.