UNPKG

google-recaptcha-v3

Version:

A React library for Google reCAPTCHA integration with both hooks and components supporting v2 and v3

411 lines (333 loc) 11.1 kB
# React Google Recaptcha A clean, modern React library for Google reCAPTCHA integration with both hooks and components supporting v2 and v3. ## Install: ```bash npm i google-recaptcha-v3 ``` ## Import to React: ### Hook (v3 only): ```tsx import { useGoogleRecaptcha } from "google-recaptcha-v3"; ``` ### Component (supports both v2 and v3): ```tsx import { GoogleRecaptcha } from "google-recaptcha-v3"; ``` ## Hook Usage (v3 only) ### Basic Hook Usage ```tsx import React from "react"; import { useGoogleRecaptcha } from "google-recaptcha-v3"; const YourComponent = () => { const siteKey = "YOUR_SITE_KEY"; const action = "submit"; const { token, error, isLoading } = useGoogleRecaptcha(siteKey, action); if (isLoading) { return <div>Loading reCAPTCHA...</div>; } if (error) { return <div>Error: {error}</div>; } // You can use token to send request to API return ( <div> {token && <p>reCAPTCHA token generated successfully!</p>} </div> ); }; export default YourComponent; ``` ## Component Usage ### reCAPTCHA v2 - Basic Usage ```tsx import React, { useRef } from "react"; import { GoogleRecaptcha, GoogleRecaptchaRef } from "google-recaptcha-v3"; const YourComponent = () => { const recaptchaRef = useRef<GoogleRecaptchaRef>(null); const siteKey = "YOUR_SITE_KEY"; const handleSubmit = async () => { if (recaptchaRef.current) { const token = await recaptchaRef.current.execute(); if (token) { console.log("reCAPTCHA token:", token); // Send request to your API with the token } } }; const handleChange = (token: string | null) => { console.log("reCAPTCHA token changed:", token); }; return ( <div> <GoogleRecaptcha ref={recaptchaRef} sitekey={siteKey} onChange={handleChange} onExpired={() => console.log("reCAPTCHA expired")} onErrored={(error) => console.error("reCAPTCHA error:", error)} /> <button onClick={handleSubmit}>Submit</button> </div> ); }; export default YourComponent; ``` ### reCAPTCHA v2 - Advanced Configuration ```tsx import React, { useRef } from "react"; import { GoogleRecaptcha, GoogleRecaptchaRef } from "google-recaptcha-v3"; const YourComponent = () => { const recaptchaRef = useRef<GoogleRecaptchaRef>(null); const siteKey = "YOUR_SITE_KEY"; const handleSubmit = async () => { const token = recaptchaRef.current?.getResponse(); if (token) { // Send request to your API with the token console.log("Submitting with token:", token); } else { alert("Please complete the reCAPTCHA"); } }; const handleReset = () => { recaptchaRef.current?.reset(); }; return ( <div> <GoogleRecaptcha ref={recaptchaRef} sitekey={siteKey} theme="dark" size="compact" hl="vi" // Vietnamese onChange={(token) => console.log("Token:", token)} onExpired={() => { console.log("reCAPTCHA expired"); handleReset(); }} onErrored={(error) => console.error("Error:", error)} style={{ margin: "20px 0" }} /> <div> <button onClick={handleSubmit}>Submit</button> <button onClick={handleReset}>Reset</button> </div> </div> ); }; export default YourComponent; ``` ### reCAPTCHA v3 - Component Usage ```tsx import React, { useRef } from "react"; import { GoogleRecaptcha, GoogleRecaptchaRef } from "google-recaptcha-v3"; const YourComponent = () => { const recaptchaRef = useRef<GoogleRecaptchaRef>(null); const siteKey = "YOUR_SITE_KEY"; const handleSubmit = async () => { try { const token = await recaptchaRef.current?.executeAsync(); if (token) { console.log("v3 token:", token); // Send request to your API with the token } } catch (error) { console.error("Failed to get token:", error); } }; return ( <div> <GoogleRecaptcha ref={recaptchaRef} sitekey={siteKey} version="v3" action="submit" onLoad={() => console.log("reCAPTCHA v3 loaded")} onErrored={(error) => console.error("reCAPTCHA error:", error)} /> <button onClick={handleSubmit}>Submit with v3</button> </div> ); }; export default YourComponent; ``` ### Invisible reCAPTCHA ```tsx import React, { useRef } from "react"; import { GoogleRecaptcha, GoogleRecaptchaRef } from "google-recaptcha-v3"; const YourComponent = () => { const recaptchaRef = useRef<GoogleRecaptchaRef>(null); const siteKey = "YOUR_SITE_KEY"; const handleSubmit = async () => { try { // For invisible reCAPTCHA, execute when user submits const token = await recaptchaRef.current?.executeAsync(); if (token) { console.log("Invisible reCAPTCHA token:", token); // Send request to your API with the token } } catch (error) { console.error("Failed to execute invisible reCAPTCHA:", error); } }; return ( <div> <GoogleRecaptcha ref={recaptchaRef} sitekey={siteKey} size="invisible" badge="bottomright" onLoad={() => console.log("Invisible reCAPTCHA loaded")} onErrored={(error) => console.error("Error:", error)} /> <button onClick={handleSubmit}>Submit (Invisible reCAPTCHA)</button> </div> ); }; export default YourComponent; ``` ### Advanced Hook Usage ```tsx import React from "react"; import { useGoogleRecaptcha, ReCaptchaOptions } from "google-recaptcha-v3"; const YourComponent = () => { const siteKey = "YOUR_SITE_KEY"; const action = "submit"; const options: ReCaptchaOptions = { language: "vi" }; // Vietnamese language const { token, error, isLoading, refreshToken, executeRecaptcha } = useGoogleRecaptcha(siteKey, action, options); const handleSubmit = async () => { try { const newToken = await executeRecaptcha(); if (newToken) { // Send request to your API with the token console.log("New token:", newToken); } } catch (err) { console.error("Failed to get reCAPTCHA token:", err); } }; return ( <div> <button onClick={handleSubmit} disabled={isLoading}> {isLoading ? "Loading..." : "Submit"} </button> <button onClick={refreshToken} disabled={isLoading}> Refresh Token </button> {error && <p style={{ color: "red" }}>Error: {error}</p>} {token && <p style={{ color: "green" }}>Token ready!</p>} </div> ); }; export default YourComponent; ``` ## API Reference ### Hook API #### `useGoogleRecaptcha(siteKey, action, options?)` ##### Parameters: - `siteKey` (string): Your Google reCAPTCHA v3 site key - `action` (string): The action name for this reCAPTCHA execution - `options` (ReCaptchaOptions, optional): Configuration options - `language` (string, optional): Language code (default: "en") ##### Returns: - `token` (string | null): The reCAPTCHA token - `error` (string | null): Error message if something went wrong - `isLoading` (boolean): Loading state - `refreshToken` (function): Function to refresh the token - `executeRecaptcha` (function): Function to manually execute reCAPTCHA ### Component API #### `<GoogleRecaptcha />` Props ##### Required Props: - `sitekey` (string): Your Google reCAPTCHA site key ##### Optional Props: - `version` ("v2" | "v3"): reCAPTCHA version (default: "v2") - `theme` ("light" | "dark"): Visual theme (v2 only, default: "light") - `size` ("compact" | "normal" | "invisible"): Widget size (default: "normal") - `type` ("image" | "audio"): Challenge type (v2 only, default: "image") - `action` (string): Action name for v3 (default: "submit") - `hl` (string): Language code (default: "en") - `badge` ("bottomright" | "bottomleft" | "inline"): Badge position for invisible (default: "bottomright") - `tabindex` (number): Tab index for accessibility - `isolated` (boolean): Isolated mode - `className` (string): CSS class name - `style` (React.CSSProperties): Inline styles ##### Callback Props: - `onChange` ((token: string | null) => void): Called when token changes - `onExpired` (() => void): Called when token expires - `onErrored` ((error: Error) => void): Called when error occurs - `onLoad` (() => void): Called when reCAPTCHA loads #### Component Ref Methods When using `useRef<GoogleRecaptchaRef>()`: - `execute()`: Promise<string | null> - Execute reCAPTCHA and get token - `executeAsync()`: Promise<string> - Execute reCAPTCHA and get token (throws on failure) - `reset()`: void - Reset the reCAPTCHA widget (v2 only) - `getResponse()`: string | null - Get current response token (v2 only) ## TypeScript Support This package includes full TypeScript support with exported interfaces: ```tsx import { useGoogleRecaptcha, ReCaptchaResponse, ReCaptchaOptions } from "google-recaptcha-v3"; ``` ## Features ### Hook Features (v3 only) - ✅ Clean and modern React hook - ✅ Full TypeScript support - ✅ Automatic script loading and cleanup - ✅ Error handling - ✅ Loading states - ✅ Manual token refresh - ✅ Language support - ✅ Zero dependencies (peer dependency: React >=16.8.0) ### Component Features (v2 & v3) - ✅ Supports both reCAPTCHA v2 and v3 - ✅ Full component-based implementation with ref support - ✅ All reCAPTCHA v2 props (theme, size, type, etc.) - ✅ Invisible reCAPTCHA support - ✅ Comprehensive callback handling (onChange, onExpired, onErrored, onLoad) - ✅ Imperative API through refs (execute, reset, getResponse) - ✅ Flexible styling and positioning options - ✅ Language and localization support - ✅ Full TypeScript interfaces and type safety # Backend Integration ## Verify reCAPTCHA token from React with NestJS Back-End: ### Create RecaptchaMiddleware by CMD: ```bash nest generate middleware recaptcha ``` ### Add Sample code to RecaptchaMiddleware: ```ts import { Injectable, NestMiddleware } from '@nestjs/common'; import { Request, Response, NextFunction } from 'express'; import axios from 'axios'; @Injectable() export class RecaptchaMiddleware implements NestMiddleware { private key = 'YOUR_SITE_SECRET_KEY'; async use(req: Request, res: Response, next: NextFunction) { const recaptchaToken = req.body.recaptchaToken; if (!recaptchaToken) { return res.status(400).json({ message: 'Missing recaptchaToken' }); } try { const response = await axios.post( `https://www.google.com/recaptcha/api/siteverify?secret=${this.key}&response=${recaptchaToken}`, {}, ); const { success } = response.data; if (!success) { return res.status(401).json({ message: 'Invalid recaptchaToken' }); } next(); } catch (error) { console.error('Recaptcha verification error:', error); return res.status(500).json({ message: 'Internal Server Error' }); } } } ``` ### Author Copyright 2024 mia nguyen x thind9xdev Licensed under the MIT License