Skip to content

Instantly share code, notes, and snippets.

@siexp
Created June 27, 2025 08:33
Show Gist options
  • Save siexp/1d82d1ed5b12cf16371b2e3542a26c38 to your computer and use it in GitHub Desktop.
Save siexp/1d82d1ed5b12cf16371b2e3542a26c38 to your computer and use it in GitHub Desktop.
google captcha example
// Frontend
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { LoginProvider} from './pages/LoginContext';
import { WalletProvider} from './pages/WalletContext';
import { RecaptchaProvider } from './pages/RecaptchaProvider'
ReactDOM.render(
<React.StrictMode>
<LoginProvider>
<WalletProvider>
// apply captcha on as POST request interceptor
<RecaptchaProvider>
<App />
</RecaptchaProvider>
</WalletProvider>
</LoginProvider>
</React.StrictMode>,
document.getElementById('root')
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
// Backend
import { Middleware } from "@loopback/rest";
const fetch = require("isomorphic-fetch");
export const reCaptchaV3: Middleware = async (middlewareCtx, next) => {
const { request, response } = middlewareCtx;
try {
if (request.method === "POST" || request.method === "PUT") {
const token = request.header("X-Recaptcha");
if (token === undefined || token === "") {
response.status(400).send({
statusCode: 400,
name: "Error",
message: "reCaptcha header is not provided",
});
}
// todo to env
const secret_key = "secret_key";
const url = `https://www.google.com/recaptcha/api/siteverify?secret=${secret_key}&response=${token}`;
const checkToken = async (req: any, res: any) => {
const body = await fetch(url, {
method: "post",
});
const googleResp = await body.json();
if (!googleResp.success) {
res.status(400).send({
statusCode: 400,
name: "Error",
message:
"errors in reCaptcha check: " +
googleResp["error-codes"].join(","),
});
}
};
await checkToken(request, response);
}
const result = await next();
return result;
} catch (err) {
// Catch errors from downstream middleware
console.log(
"Error received for %s %s",
request.method,
request.originalUrl
);
throw err;
}
};
// Frontend
import { useGoogleReCaptcha } from 'react-google-recaptcha-v3';
import { useEffect } from 'react';
export const Recaptcha = () => {
const { executeRecaptcha } = useGoogleReCaptcha();
const { fetch: originalFetch } = window;
const handleReCaptchaVerify = async () => {
try {
if (!executeRecaptcha) {
throw new Error('Execute recaptcha not yet available');
}
const token = await executeRecaptcha('login');
if (!token) {
throw new Error('Recaptcha token is empty');
}
localStorage.setItem('recaptchaToken', token);
return token;
} catch (error) {
console.error('Recaptcha verification failed:', error.message);
return null;
}
};
const interceptFetch = async (resource, options) => {
const isPostRequest = options?.method?.toLowerCase() === 'post' ||
options?.method?.toLowerCase() === 'put';
if (isPostRequest) {
const token = await handleReCaptchaVerify();
if (token) {
options = {
...options,
headers: {
...options?.headers,
'X-Recaptcha': token,
}
};
}
}
return originalFetch(resource, options);
};
useEffect(() => {
window.fetch = async (...args) => {
const [resource, options] = args;
return interceptFetch(resource, options);
};
return () => {
window.fetch = originalFetch;
};
}, [executeRecaptcha]);
return null;
};
// Frontend
import { GoogleReCaptchaProvider } from 'react-google-recaptcha-v3';
export const RecaptchaProvider= props =>{
return(
<GoogleReCaptchaProvider
reCaptchaKey="reCaptchaKey"
scriptProps={{
appendTo: 'head', // optional, default to "head", can be "head" or "body",
}}
>
{props.children}
</GoogleReCaptchaProvider>
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment