Skip to content

[6.x] Frontend Passkeys#14453

Open
duncanmcclean wants to merge 1 commit into6.xfrom
frontend-passkeys
Open

[6.x] Frontend Passkeys#14453
duncanmcclean wants to merge 1 commit into6.xfrom
frontend-passkeys

Conversation

@duncanmcclean
Copy link
Copy Markdown
Member

@duncanmcclean duncanmcclean commented Apr 7, 2026

This pull request adds passkey support to the {{ user:login_form }} and adds various other tags for setting up and managing passkeys from the frontend.

Tags

{{ user:login_form }}

To support passkeys on your login page, you will need to include the helpers script on your page:

<script src="/vendor/statamic/frontend/js/helpers.js"></script>

Then, you may combine the JS helpers & variables from the tag to add passkey support.

{{ user:login_form }}
    <!-- ... -->

    {{ if passkeys_enabled }}
        <button type="button" id="passkey-login">Login with Passkey</button>

        <script>
            document.getElementById('passkey-login').addEventListener('click', () => {
                Statamic.$passkeys.authenticate({
                    optionsUrl: '{{ passkey_options_url }}',
                    verifyUrl: '{{ passkey_verify_url }}',
                    onSuccess: (data) => window.location = data.redirect || '/',
                    onError: (error) => alert(error.message)
                });
            });

            // Enable browser autofill for passkeys
            Statamic.$passkeys.initAutofill({
                optionsUrl: '{{ passkey_options_url }}',
                verifyUrl: '{{ passkey_verify_url }}',
                onSuccess: (data) => window.location = data.redirect || '/'
            });
        </script>
    {{ /if }}
{{ /user:login_form }}

Important

For browser autofill to work, your email input must have autocomplete="username webauthn".

{{ user:passkey_form }}

The passkey form allows you to create passkeys from the frontend.

{{ user:passkey_form }}
    <input type="text" id="passkey-name" placeholder="Passkey name (e.g., My Laptop)">
    <button type="button" id="create-passkey">Create Passkey</button>

    {{ if success }}
        <p>Passkey created successfully!</p>
    {{ /if }}

    {{ if errors }}
        <ul>
            {{ errors }}
                <li>{{ value }}</li>
            {{ /errors }}
        </ul>
    {{ /if }}

    <script>
        document.getElementById('create-passkey').addEventListener('click', () => {
            const name = document.getElementById('passkey-name').value || 'My Passkey';

            Statamic.$passkeys.register({
                optionsUrl: '{{ create_url }}',
                verifyUrl: '{{ store_url }}',
                name: name,
                onSuccess: () => location.reload(),
                onError: (error) => alert(error.message)
            });
        });
    </script>
{{ /user:passkey_form }}

{{ user:passkeys }}

This tag allows you to loop through your passkeys.

{{ user:passkeys as="passkeys" }}
    {{ if passkeys }}
        <h3>Your Passkeys</h3>
        <ul>
            {{ passkeys }}
                <li>
                    <strong>{{ name }}</strong>
                    {{ if last_login }}
                        <span>Last used: {{ last_login format="M j, Y g:i A" }}</span>
                    {{ else }}
                        <span>Never used</span>
                    {{ /if }}

                    {{ user:delete_passkey_form :id="id" }}
                        <button type="submit" onclick="return confirm('Delete this passkey?')">
                            Delete
                        </button>
                    {{ /user:delete_passkey_form }}
                </li>
            {{ /passkeys }}
        </ul>
    {{ else }}
        <p>You haven't set up any passkeys yet.</p>
    {{ /if }}
{{ /user:passkeys }}

Variables:

  • id - Passkey identifier
  • name - User-defined passkey name
  • last_login - Last time the passkey was used
  • delete_url - URL to delete this passkey

{{ user:delete_passkey_form }}

This tag renders a form to delete a passkey. Most useful inside a {{ user:passkeys }} loop.

{{ user:delete_passkey_form :id="id" }}
    <button type="submit">Delete</button>
{{ /user:delete_passkey_form }}

Statamic.$passkeys JavaScript API

The frontend helpers script (/vendor/statamic/frontend/js/helpers.js) now exposes Statamic.$passkeys with:

  • authenticate(options) - Login with a passkey
  • register(options) - Register a new passkey
  • initAutofill(options) - Enable browser autofill for passkeys
  • cancel() - Cancel in-progress operations
  • supported - Browser support check

Docs PR: TODO

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant