DEV Community

Cover image for Integrating Nuxt 3 with Recaptcha v3 for Token Handling 🤖🔐
Fitra Rahmamuliani
Fitra Rahmamuliani

Posted on • Edited on

Integrating Nuxt 3 with Recaptcha v3 for Token Handling 🤖🔐

Introduction

Embarking on the journey of web development with Nuxt 3 and Recaptcha v3 can be both thrilling and challenging. Today, I tried unveil a solution that simplifies the integration process, especially when dealing with the mysterious g-recaptcha-token that being needed by the API. We need to provide it as a field when submitting a post request to the API for backend purpose: to make sure that the recaptcha token received is matching with the setup of the recaptcha token saved from the backend. If you've ever struggled with the token being undefined in production even though we already trying to use the tutorial from the vue-recaptcha-v3, me too!

In this article, I will unravel the intricacies and provide a step-by-step guide to empower developers with javascript only (no typescript) in their quest for a flawless integration. Hope it will helps you.

Part 1: Plugins - The Gateway to Recaptcha Power

Before started, please make sure that you already install the vue-recaptcha-v3.

Plugins serve as the gateway to injecting external functionalities into your Nuxt 3 project. To kickstart the integration process, create a dedicated plugin for Recaptcha v3 on plugins/recaptcha.js.

// plugins/recaptcha.js
import { VueReCaptcha } from 'vue-recaptcha-v3'
// The plugin enables the usage of Google reCAPTCHA in a Nuxt.js application
// by registering the VueReCaptcha plugin with the necessary configuration options.
export default defineNuxtPlugin(nuxtApp => {
  const config = useRuntimeConfig()

  const options = {
    siteKey: config.public.RECAPTCHA_SITE_KEY,
    loaderOptions: {
      autoHideBadge: true,
      useRecaptchaNet: true,
      renderParameters: {
        hl: 'id'
      }
    }
  }
  nuxtApp.vueApp.use(VueReCaptcha, options)
})

Enter fullscreen mode Exit fullscreen mode

Part 2: Composable - The Art of Reusable Logic

Create a composable to encapsulate the logic for handling Recaptcha interactions. This composable will be the engine that drives the token generation process.

Please make sure that you save it on the composables folder.

// composables/useGoogleRecaptcha.js

import { useReCaptcha } from 'vue-recaptcha-v3'
/**
 * The exported executeRecaptcha function allows
 * you to execute reCAPTCHA actions
 * and retrieve the reCAPTCHA token along with the header options
 * to be used in subsequent requests.
 */
export default () => {
  const recaptchaInstance = useReCaptcha()
  const executeRecaptcha = async action => {
    /**
     * Wait for the recaptchaInstance to be loaded
     * by calling the recaptchaLoaded method.
     * This ensures that the reCAPTCHA library is fully loaded
     * and ready to execute reCAPTCHA actions.
     */
    await recaptchaInstance?.recaptchaLoaded()
    const token = await recaptchaInstance?.executeRecaptcha(action)
    const headerOptions = {
      headers: {
        'google-recaptcha-token': token
      }
    }
    return { token, headerOptions }
  }
  return { executeRecaptcha }
}

Enter fullscreen mode Exit fullscreen mode

Part 3: Calling the Function - Bridging the Frontend and Backend

Now that we have our Recaptcha composable ready, let's integrate it into our component and call the function whenever needed.

In this example, we use NuxtApiParty for handling the api that they will generate the useApiData based on our config. You can learn more about NuxtApiParty here: https://nuxt-api-party.byjohann.dev/

<template>
  <!-- insert code for your component's template -->
</template>

<script setup>
// other functions

const { executeRecaptcha } = useGoogleRecaptcha()

// the function where you submit the form 
const submitForm = async values => {
  isSubmitting.value = true
const { token } = await executeRecaptcha('submit')
// console.log(token) -> to make sure there is the token

// combine the form value with g-recaptcha-response that we need to send via api
const bodyData = {
    ...formData.value,
    'g-recaptcha-response': token
}

const { pending, error } = await useApiData(
    `/api/form_submissions`,
    {
      method: 'post',
      cache: false,
      body: bodyData
    }
  )

  if (error.value) {
    isSubmitting.value = pending.value
    showFail.value = true
  } else {
    isSubmitting.value = pending.value
    clearForm()
    showSuccess.value = true
  }
}

// other functions 
</script>
Enter fullscreen mode Exit fullscreen mode

Additional step (if your plugins are not being called)

All plugins inside are auto-registered, you don't need to add them to your nuxt.config separately.
source: Thanks to
Thiru for sending this source https://nuxt.com/docs/guide/directory-structure/plugins

If you have already registered but are not being called (special case), you can try this additional step:

Nuxt Config - Configuring the Nexus of Nuxt 3 and Recaptcha

Now, let's configure Nuxt to incorporate the Recaptcha plugin seamlessly. Open your nuxt.config.ts file and include the plugin in the plugins array.

// nuxt.config.ts

// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
  // {insert CODE for other Nuxt config options}

  // Include the Recaptcha plugin
  plugins: [{src: '~/plugins/recaptcha.js'}],

  // {insert CODE for other Nuxt config options}
};
Enter fullscreen mode Exit fullscreen mode

Conclusion:

Congratulations! You've embarked on a journey to seamlessly integrate Nuxt 3 with Recaptcha v3, overcoming the challenges associated with g-recaptcha-token (getting the token sent to the API). This solution ensures a smooth transition from development to production, empowering developers to create secure and reliable web applications. Happy coding!

Reference:

Top comments (9)

Collapse
 
thiruppathi profile image
Thiru

Thanks for the article!

Suggestion: As mentioned here
All plugins inside are auto-registered, you don't need to add them to your nuxt.config separately. Part 2 is not needed.

Collapse
 
fitrakun profile image
Fitra Rahmamuliani

Thank you for your suggestion. I revised my article and create an additional steps in case the auto-registered is not working 😊

Collapse
 
afrijaldz profile image
Afrijal Dzuhri • Edited

Thanks for the article, it helps me. But i have a correction here

that

const token = await recaptchaInstance?.executeRecaptcha(action.name)
Enter fullscreen mode Exit fullscreen mode

should be

const token = await recaptchaInstance?.executeRecaptcha(action) 
Enter fullscreen mode Exit fullscreen mode

because when you await executeRecaptcha('submit') the action will always undefined

Collapse
 
fitrakun profile image
Fitra Rahmamuliani

Thank you for your correction! I didn't know that the action will always be undefined because using action.name always works for me. I revised my article already 😆

Collapse
 
faridsa profile image
farid

Nice post! Thank you.
Now it loads google recaptcha script from the beginning, which has its downside in terms of google core vitals.
How can I load the script, only when I need to show a form?

Collapse
 
__aea5cd1371 profile image
Баястан Нурбек

have u solved it?

Collapse
 
faridsa profile image
farid

Not yet, just because a lack of time due to project priorities. I've see some comments in some place recommending to use cloudflare for better performance with google analytics, I think, if it is the case, it should be useful for recaptcha too.

Collapse
 
hendisantika profile image
Hendi Santika

Nice article.

Do You push it into GitHub?

Can I see it?

Thanks

Collapse
 
jolanta_kazlauskien_6ed3 profile image
Jolanta Kazlauskienė

I'm getting token undefined... I'm not sure what's wrong