Nuxt Turnstile

repository·main·Indexed 43 days ago

https://github.com/nuxt-modules/turnstile

A Nuxt 3 module for Cloudflare Turnstile integration, providing bot protection via the <NuxtTurnstile> Vue component and server-side Nitro utilities. Features include the verifyTurnstileToken helper, a configurable validation endpoint at /_turnstile/validate, and the useScriptCloudflareTurnstile composable for script management. Version 1.1.3.

Tokens
3.3K
Snippets
12
Records
14
Agent score
53%

What's inside Nuxt Turnstile

  1. Verify Turnstile tokens on the server

    main

    To validate a token on your Nitro server routes, you have two primary methods:

    1. Use the verifyTurnstileToken helper

    Import the auto-imported verifyTurnstileToken utility directly into your server route handler.

    2. Use the built-in validation endpoint

    Enable the endpoint in your nuxt.config.ts:

    turnstile: {
      siteKey: '<your-site-key>',
      addValidateEndpoint: true
    }

    Then, call /_turnstile/validate from your client-side code.

    // server/api/validateTurnstile.ts
    
    export default defineEventHandler(async (event) => {
      const { token } = await readBody(event)
    
      if (!token) {
        throw createError({
          statusCode: 422,
          statusMessage: 'Token not provided.',
        })
      }
    
      return await verifyTurnstileToken(token)
    })
  2. Add TypeScript types for Cloudflare Turnstile

    main

    For full TypeScript support when working with Turnstile types, install the @types/cloudflare-turnstile package as a development dependency.

    pnpm add -D @types/cloudflare-turnstile
  3. Install @nuxtjs/turnstile

    main

    To integrate Cloudflare Turnstile into your Nuxt 3 application, follow these steps:

    1. Obtain a free sitekey and secret key from Cloudflare Turnstile.
    2. Install @nuxt/scripts as a dependency.
    3. Add the module using the Nuxt CLI:
    npx nuxi@latest module add turnstile
  4. Configure @nuxtjs/turnstile

    main

    Configure the module in your nuxt.config.ts. You must provide a siteKey and a secretKey (via runtimeConfig or an environment variable).

    Configuration Options:

    • siteKey: Your Cloudflare Turnstile site key.
    • secretKey: Your Cloudflare Turnstile secret key. Can be set in runtimeConfig or via the NUXT_TURNSTILE_SECRET_KEY environment variable.
    • secretKeyPath: A path to a file containing the secret key. This is read at build-time and overrides other secretKey settings.
    • addValidateEndpoint: Boolean. If true, enables a built-in validation endpoint at /_turnstile/validate.

    Environment Variable Overrides:

    • NUXT_PUBLIC_TURNSTILE_SITE_KEY overrides the site key.
    • NUXT_TURNSTILE_SECRET_KEY overrides the secret key.
    export default defineNuxtConfig({
      modules: ['@nuxtjs/turnstile'],
    
      turnstile: {
        siteKey: '<your-site-key>',
      },
    
      runtimeConfig: {
        turnstile: {
          // This can be overridden at runtime via the NUXT_TURNSTILE_SECRET_KEY
          // environment variable.
          secretKey: '',
        },
      },
    })
  5. Enable the Turnstile validation endpoint

    main

    To automatically add a server-side Nitro endpoint for validating Cloudflare Turnstile tokens, set addValidateEndpoint to true in your module configuration. This creates a POST handler at /_turnstile/validate.

    // nuxt.config.ts
    export default defineNuxtConfig({
      modules: ['@nuxtjs/turnstile'],
      turnstile: {
        addValidateEndpoint: true
      }
    })
    export default defineNuxtConfig({
      modules: ['@nuxtjs/turnstile'],
      turnstile: {
        addValidateEndpoint: true
      }
    })
  6. Use the <NuxtTurnstile> component

    main

    The <NuxtTurnstile> component is an auto-imported Vue component used to render the Turnstile widget.

    • Token Access: Use v-model to bind the validation token to a variable.
    • Form Integration: Cloudflare automatically adds a hidden form element named cf-turnstile-response to your form. Alternatively, you can send the token explicitly via the v-model value.
    • Customization: You can pass an options object to configure the widget and use the element prop to change the default <div> wrapper to a different element.
    • Token Lifecycle: Tokens are valid for 300s and are automatically revalidated after 250s.
    • Manual Reset: Because tokens are invalidated after server-side processing, you must regenerate the token for subsequent submissions (e.g., in a multi-submission form) using the reset() method via a template ref.
    <template>
      <div>
        <form @submit.prevent="onSubmit">
          <NuxtTurnstile v-model="token" />
          <input type="submit" />
        </form>
      </div>
    </template>
  7. Reset the Turnstile token manually

    main

    If you are using a component that requires multiple validations (like a form that stays on the page after submission), use a template ref to call the reset() method on the <NuxtTurnstile> component.

    <template>
      <NuxtTurnstile ref="turnstile" />
      <button @click="turnstile.reset()">Reset token in template</button>
      <button @click="reset()">Reset token from handler</button>
    </template>
    
    <script setup>
      // you can call this template ref anything
      const turnstile = ref()
    
      function reset() {
        turnstile.value?.reset()
      }
    </script>
  8. Configure the Nuxt Turnstile module

    main

    The @nuxtjs/turnstile module can be configured via the turnstile key in your nuxt.config.ts.

    Configuration Options

    OptionTypeDefaultDescription
    secretKeystring1x0000000000000000000000000000000AA (dev only)Your Cloudflare Turnstile secret key. It is recommended to set this via runtimeConfig.turnstile.secretKey or the NUXT_TURNSTILE_SECRET_KEY environment variable.
    secretKeyPathstringundefinedPath to a file containing the secret key. The module will read the file content to populate the secretKey.
    siteKeystring1x0000000000000000000000000000000AA (dev only)Your Cloudflare Turnstile site key.
    addValidateEndpointbooleanfalseIf set to true, a Nitro endpoint is added at /_turnstile/validate to validate tokens.
    export interface ModuleOptions {
      secretKey?: string
      secretKeyPath?: string
      siteKey?: string
      addValidateEndpoint?: boolean
    }
  9. Verify Turnstile tokens in server routes

    main

    The module provides a server-side utility verifyTurnstileToken that can be used within your Nitro server routes to verify Cloudflare tokens. This utility is automatically imported into your Nitro environment.

    // server/api/my-endpoint.post.ts
    export default defineEventHandler(async (event) => {
      const body = await readBody(event)
      const isValid = await verifyTurnstileToken(body.token)
      
      if (!isValid) {
        throw createError({ statusCode: 403, statusMessage: 'Invalid Turnstile token' })
      }
      
      // Proceed with logic
    })
  10. Verify Turnstile tokens on the server with verifyTurnstileToken

    main

    Use the verifyTurnstileToken utility to validate a Cloudflare Turnstile token on your server. This function performs a POST request to the Cloudflare siteverify endpoint using the secretKey configured in your Nuxt runtime configuration.

    Parameters:

    • token (string): The Turnstile token received from the client.
    • event (H3Event, optional): The H3 event object, required to access the runtime configuration via useRuntimeConfig in Nitro environments.
    • signal (AbortSignal, optional): An optional signal to abort the fetch request.

    Returns:

    • A Promise that resolves to a TurnstileValidationResponse object containing the verification result from Cloudflare.
    import { verifyTurnstileToken }
    
    export default defineEventHandler(async (event) => {
      const body = await readBody(event)
      const token = body.token
    
      const isValid = await verifyTurnstileToken(token, event)
    
      if (!isValid.success) {
        throw createError({
          statusCode: 403,
          statusMessage: 'Invalid Turnstile token'
        })
      }
    
      return { success: true }
    })
  11. Load the Cloudflare Turnstile script with useScriptCloudflareTurnstile

    main

    Use the useScriptCloudflareTurnstile composable to load the Cloudflare Turnstile API script (https://challenges.cloudflare.com/turnstile/v0/api.js) into your Nuxt application. This composable leverages @nuxt/scripts to manage the script lifecycle and provides access to the window.turnstile object once the script is loaded.

    It accepts an optional userOptions argument of type RegistryScriptInput to customize the script loading behavior (e.g., loading strategy, triggers, or dependencies).

    // Example usage in a component or composable
    const { isLoading, isReady } = useScriptCloudflareTurnstile();
    
    // You can check if the turnstile object is available on the window
    if (isReady.value && window.turnstile) {
      // Initialize Turnstile
    }
  12. Configure Turnstile render options

    main

    When rendering a Turnstile widget, you can pass a TurnstileRenderOptions object to customize its behavior, appearance, and callbacks.

    Key options include:

    • sitekey: The sitekey associated with your widget configuration.
    • theme: Sets the widget theme to 'dark', 'light', or 'auto' (default).
    • appearance: Controls visibility. Options are 'always' (default), 'execute', or 'interaction-only'.
    • language: A custom language setting (e.g., 'en', 'en-US', or 'auto').
    • action: A string used to differentiate widgets in analytics.
    • cData: A custom payload attached to the challenge and returned upon validation.
    • callback: A function invoked upon successful challenge completion, receiving the token as a string.
    • expired-callback: A function invoked when a challenge expires.
    • error-callback: A function invoked when a network error occurs.
    • tabindex: The tabindex for the iframe (default is 0).
    const options: TurnstileRenderOptions = {
      sitekey: 'YOUR_SITE_KEY',
      theme: 'dark',
      appearance: 'always',
      callback: (token: string) => {
        console.log('Success! Token:', token);
      },
      'error-callback': () => {
        console.error('Network error occurred');
      }
    };