svelte-turnstile
TypeScript icon, indicating that this package has built-in type declarations

0.5.0 • Public • Published

Svelte Turnstile

Works with Svelte 3 & 4!

Cloudflare's Turnstile is a new CAPTCHA alternative, this library allows you to easily integrate it into your svelte projects.

Installing

npm install svelte-turnstile -D

Demo

https://svelte-turnstile.pages.dev/

Using

The only required prop is the siteKey which you can get from adding a site here.

<script>
    import { Turnstile } from 'svelte-turnstile';
</script>

<Turnstile siteKey="SITE_KEY" />

Props

Prop Type Description Required
siteKey string sitekey for your website
theme 'light' | 'dark' | 'auto' colour theme of the widget (defaults to auto)
size 'normal' | 'compact' size of the widget (defaults to normal)
action string A string that can be used to differentiate widgets, returned on validation
cData string A string that can attach customer data to a challange, returned on validation
tabIndex number Used for accessibility (defaults to 0)
forms boolean if true the response token will be a property on the form data (default true)
formsField string the name of the input which will appear on the form data (default cf-turnstile-response)
retry 'auto' | 'never' should the widget automatically retry to obtain a token if it did not succeed (default auto)
retryInterval number if retry is true, this controls the time between attempts in milliseconds (default 8000)
language `SupportedLanguage 'auto'` the language turnstile should use (default auto)
execution `'render' 'execute'` controls when to obtain the token of the widget (default render)
appearance `'always' 'execute' 'interaction-only'`

For more information about some of the props and a list of SupportedLanguage's checkout the Cloudflare Documentation.

Events

Event Data Description
turnstile-error {} Emitted when a user fails verification
turnstile-expired {} Emitted when a challenge expires and does not reset the widget
turnstile-timeout {} Emitted when a challenge expires and does reset the widget
turnstile-callback { token: string } Emitted when a user passes a challenge

Validate CAPTCHA

We need to validate the captcha token server side before we do any action on the server, this is to ensure no forgery occured. We can create a simple validate function:

If you are using a HTML Form and POSTing to a server you can get the cf-turnstile-response (or what you configured it to using the formsField option) property to get the token, otherwise you can use the on:turnstile-callback event in svelte to keep track of the token and send it to your backend.

interface TokenValidateResponse {
    'error-codes': string[];
    success: boolean;
    action: string;
    cdata: string;
}

async function validateToken(token: string, secret: string) {
    const response = await fetch(
        'https://challenges.cloudflare.com/turnstile/v0/siteverify',
        {
            method: 'POST',
            headers: {
                'content-type': 'application/json',
            },
            body: JSON.stringify({
                response: token,
                secret: secret,
            }),
        },
    );

    const data: TokenValidateResponse = await response.json();

    return {
        // Return the status
        success: data.success,

        // Return the first error if it exists
        error: data['error-codes']?.length ? data['error-codes'][0] : null,
    };
}

SvelteKit Example

In SvelteKit we can use form actions to easily setup a form with a captcha:

routes/login/+page.svelte

<script>
    import { Turnstile } from 'svelte-turnstile';

    /** @type {import('./$types').ActionData} */
    export let form;
</script>

{#if form?.error}
    <p>{form?.error}</p>
{/if}

<form method="POST" action="/login">
    <Turnstile siteKey="SITE_KEY" theme="dark" />
</form>

routes/login/+page.server.js

// Copy and paste the validateToken function from above here

export const actions = {
    default: async ({ request }) => {
        const data = await request.formData();

        const token = data.get('cf-turnstile-response') // if you edited the formsField option change this
        const SECRET_KEY = '...' // you should use $env module for secrets

        const { success, error } = await validateToken(token, SECRET_KEY);

        if (!success)
            return {
                error: error || 'Invalid CAPTCHA',
            };

        // do something, the captcha is valid!
    }
}

Resetting

If you need to manually reset the widget, you can do so by binding to the reset prop. For example:

<script lang="ts">
    let reset: () => void | undefined;
</script>

<button on:click={() => reset?.()}>
    Reset
</button>

<Turnstile bind:reset />

Support

/svelte-turnstile/

    Package Sidebar

    Install

    npm i svelte-turnstile

    Weekly Downloads

    1,615

    Version

    0.5.0

    License

    MIT

    Unpacked Size

    13.5 kB

    Total Files

    8

    Last publish

    Collaborators

    • ghostsos