Skip to content

Instantly share code, notes, and snippets.

@Steven24K
Last active May 28, 2021 08:12
Show Gist options
  • Save Steven24K/149c8d2c4dd981786bd8fd0bc919962f to your computer and use it in GitHub Desktop.
Save Steven24K/149c8d2c4dd981786bd8fd0bc919962f to your computer and use it in GitHub Desktop.
A wrapper component for Googles ReCaptcha React. This is only client side, you still need to verify the ReCaptcha server side where you receive your form data.

ReCaptcha setup

The ReCaptcha wrapper generates a client side token for you that you can pass to your backend to verify the ReCaptcha. Verifying goes against this endpoint: https://www.google.com/recaptcha/api/siteverify?secret={secret}&response={response_token}, with a POST request.

The response will be like this: { "success": true, "challenge_ts": "2021-05-28T08:05:20Z", "hostname": "testkey.google.com" } You can get your ReCaptcha tokens in your Google cloud console: https://www.google.com/recaptcha/about/

Read more developer documentation here: https://developers.google.com/recaptcha/docs/v3

You will notice that ReCaptcha is domain based and probably does not work on localhost. Google has a sollution for that. They provided you with a free pair of public and private keys you can use to test locally.

  • siteKey: 6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI
  • secret: 6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe
import * as React from 'react'
import ReCAPTCHA from "react-google-recaptcha";
// This is a demo site key provided by google for testing, since recaptcha is domain based.
// 6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI
// Google test secret (for server side verification) -> 6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe
interface ReCaptchaFormProps {
sitekey: string
children?: React.ReactNode
onSubmitOkay?: (e: any, token: string) => void
className?: string
buttonClass?: string
buttonDisabled?: boolean
buttonText: string
size: "compact" | "normal" | "invisible"
badge?: "bottomright" | "bottomleft" | "inline"
}
interface ReCaptchaFormState {
token: string
error: string
}
export class ReCaptchaForm extends React.Component<ReCaptchaFormProps, ReCaptchaFormState> {
private recaptchaRef: any
constructor(props: ReCaptchaFormProps) {
super(props)
this.state = { token: "", error: "" }
this.recaptchaRef = React.createRef()
this.onReCapthcaChange = this.onReCapthcaChange.bind(this)
this.onSubmitCaptcha = this.onSubmitCaptcha.bind(this)
}
onReCapthcaChange = (token: string) => {
this.setState(s => ({ ...s, token: token, error: "" }))
}
onSubmitCaptcha = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault()
const token = this.props.size != 'invisible' ? this.recaptchaRef.current.getValue() : await this.recaptchaRef.current.executeAsync();
if (this.state.token == token && token != "" && this.state.token != "") {
console.log("form submited, you are not a robot")
this.props.onSubmitOkay(e, token)
} else {
this.setState(s => ({ ...s, error: "Please complete the ReCaptcha" }))
}
}
render() {
return <form onSubmit={this.onSubmitCaptcha} className={this.props.className}>
{this.props.children}
{this.state.error != "" && <div>{this.state.error}</div>}
{/*ReCaptcha component */}
<ReCAPTCHA
ref={this.recaptchaRef}
sitekey={this.props.sitekey}
onChange={this.onReCapthcaChange}
onErrored={() => console.log("ReCaptcha failed")}
onExpired={() => this.setState(s => ({ ...s, token: "" }))}
badge={this.props.badge}
size={this.props.size}
type="image"
theme="light"
/>
<button
className={this.props.buttonClass}
disabled={this.props.buttonDisabled == undefined ? false : this.props.buttonDisabled}
type="submit"
>
{this.props.buttonText}
</button>
</form>
}
}
@Steven24K
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment