How To Implement Google reCAPTCHA v3 in Flutter Web
A Basic Guide to Developers for embedding the Google reCAPTCHA v3 in Flutter Web.
THE FEAR OF BOT
As a developer, whenever you create forms to get the data from a user on the web, you always need to be alert from spam data. Hackers can inject scripted bots to fill the form with malicious code activity and access your site’s backend.
Google introduced the concept of reCAPTCHA
, a free and secure service¹ to handle the fear of bots. From the website, it states that
reCAPTCHA v3 helps you detect abusive traffic on your website without user interaction. Instead of showing a CAPTCHA challenge, reCAPTCHA v3 returns a score so you can choose the most appropriate action for your website.
CLIENT SIDE SETUP
Before start coding, you would need to register the site on which the reCAPTCHA v3
would be used. Follow the below steps:
- Visit the Google reCAPTCHA site , click on “v3 Admin Console” & sign in with your Google account.
2. Select “reCAPTCHA v3” and type “localhost ” (if you’re not ready for a production environment), accept the terms & hit the “Submit” button.
3. After successful registration, note down the reCAPTCHA site & secret keys.
REQUIRED PUBSPEC PACKAGES
In the pubspec.yaml
file, add the below packages under dependencies
.
THE BIG PICTURE
For the sake of simplicity, we will be creating a MaterialApp
having a bear bone Form
widget with a “Name” TextFormField
and aSubmit
button, see Figure-I for the app widget tree structure.
As shown in Figure-II, from the client perspective, we would need to:
- Make the
main
method asynchronous. - Inside
main
, call theGRecaptchaV3.ready²
method beforerunApp
. - On hitting submit, invoke the
GRecaptchaV3.execute²
method. - Save the generated “User Response Token” in a private variable
_token
.
The client (our app) will send the _token
with the recaptcha-secret-key
as an HTTP POST Request to the server, as depicted in Figure-III.
Upon receiving the HTTP POST Request, the server validates the client’s request as depicted in Figure-IV. In this response, a score
between 0.0 to 1.0 is obtained where zero means no human interaction was found. We can say that “It’s likely a bot!” in terms of a layman³.
Depending on the nature of the site, we would define an action
and a threshold value which would interpret the obtained score
. For more information regarding score interpretation & action , refer to the reCAPTCHA documentation³.
WORKAROUND TO HANDLE CORS IN FLUTTER WEB
Because we would be making HTTP requests through out the project, you might face CORS⁴ error in Flutter Web. Below is a work-around on Stack Overflow that would assist you make request in localhost.
LET’S START CODING!
WROOM! WROOM! WROOM! Hold on your keys because we are about to start coding. Below Figure-V shows the folder structure that would be maintained through out this project.
Step 1 - Place the reCAPTCHA Site Key in index.html file.
Navigate to the web
folder, open the index.html
file and paste the below script inside the <body>
tag as shown below.
To check whether the Google reCAPTCHA v3
is working correctly on our site, invoke the GRecaptchaV3.ready
method inmain.dart
as shown in below snippet.
After running the above code, you would see the “protected by reCAPTCHA” as shown in Figure-VI below.
Step 2 - Securing The Confidential Information.
To keep the secret key & site key confidential, under the lib
folder create a config
folder with config.dart
file as shown below in the code snippet. Note: Don’t forget to add this to the .gitignore
file!
Step 3 - Create a ReCAPTCHA Response Model.
Under the lib
folder create a model
folder with recaptcha_response.dart
file, as shown below in the code snippet. This class would hold the HTTP Response obtained as a dart
object.
Step 4 - Create a ReCAPTCHA Service.
Rather than directly invoking the GRecaptchaV3
methods, we create a Service Layer or a Wrapper class that would hold all the reCAPTCHA
operations.
Let’s understand the code by breaking it up apart.
- RecaptchaService.initiate(): A wrapper for
GRecaptchaV3.ready
that would be used in themain
method before running our app. As stated in thereCAPTCHA
docs, it is essential to call theready
method before theexecute
method, see above snippet. - RecaptchaService.isNotABot(): It is invoked after the user submits the form & the submission passes all the validations. It’s a simple method which calculates the threshold value and returns true/false based upon the
_score
. - RecaptchaService._getVerificationResponse(): A private method that performs HTTP POST request to verify the client’s response token. The
GRecaptchaV3.execute
method returns a response token which is valid for two seconds. To make a valid HTTP POST request, we would check that we first receive the response token, then pass it as a POST request body parameter along with thereCAPTCHA secret key
. If the HTTP POST request succeeds, we would convert the HTTP Response to theRecaptchaResponse
model object and return it.
Step 5 - Invoke the ReCAPTCHA Service After Form Submission.
On the Submit button’s onPressed
function, we would:
- Check that the
GlobalKey<FormState>
current state is validated. If it’s valid then proceed to step 2, else tell the user to fill theNameFormField
properly. - In case of success, invoke
RecaptchaService.isNotABot()
and assign it’s value to a boolean flag_isNotABot
. - Depending on the value of
_isNotABot
, show a dialog to the user.
Step 6 - Run the app
Run the app to see the results as shown in Figure-VII.
Visit the recaptcha_v3_tutorial⁵ GitHub Repository for the full source code of this project.
Tip - Type 1s
if you wish to see the repo as in VSCode within the browser like https://github1s.com/Zujaj/recaptcha_v3_tutorial
.
Google reCAPTCHA Admin Console
Visit the Google reCAPTCHA Admin console for risk analysis. Kindly note that the readings of localhost would differ as compared to a live hosted site. Once you’re ready for production, don’t forget to change your domain from “localhost” via the Admin Console’s ⚙️ Settings Icon.
CONCLUSION
I hope this article has been fruitful in guiding you towards the safety of your web forms in Flutter Web. If you enjoyed this article, don’t press the clap button once; press it 50 times!
ACKNOWLEDGEMENT
Thanks to the Level Up Coding platform for providing me the space to learn, explore and share this precious knowledge amongst the community of Flutter Developers. I am also thankful to Muzzammil-Khan from Telic Solutions for guiding me towards the Google reCAPTCHA v3 console.
Special thanks to Bharathraj for introducing the g_recaptcha_v3 package.
REFERENCES
[1]: About Google reCAPTCHA
https://www.google.com/recaptcha/about
[2]: g_recaptcha_v3 | Flutter Package
https://pub.dev/packages/g_recaptcha_v3
[3]: Interpreting The Score | reCAPTCHA Docs
https://developers.google.com/recaptcha/docs/v3#interpreting_the_score
[4]: Cross-Origin Resource Sharing (CORS) — HTTP | MDN (mozilla.org)
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
[5]: reCAPTCHA v3 Tutorial | GitHub Repository
https://github.com/Zujaj/recaptcha_v3_tutorial