-
-
Notifications
You must be signed in to change notification settings - Fork 407
Frontend Passkeys #1883
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Frontend Passkeys #1883
Changes from 1 commit
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| --- | ||
| id: d0ed4ac0-536a-47a1-965b-202b52baddb2 | ||
| blueprint: tag | ||
| title: 'User:Delete_Passkey_Form' | ||
| description: 'Creates a form to delete a passkey' | ||
| intro: 'As the tag name suggests, it allows you to delete a passkey.' | ||
| parameters: | ||
| - | ||
| name: id | ||
| type: string | ||
| description: 'The passkey ID to delete. Required.' | ||
| - | ||
| name: redirect | ||
| type: string | ||
| description: Where the user should be taken after successfully deleting a passkey. | ||
| - | ||
| name: HTML Attributes | ||
| type: | ||
| description: 'Set HTML attributes as if you were in an HTML element. For example, `class="delete-form"`.' | ||
| related_entries: | ||
| - 38323438-4719-4a7b-ba5a-8abfe0d7dfc0 | ||
| - 7a958307-4cdb-47f3-a689-0c7de57e3ff7 | ||
| - 7432f1cb-7418-4d54-8e65-51b1ae3bcb3a | ||
| --- | ||
| ## Overview | ||
|
|
||
| The `user:delete_passkey_form` tag renders a form to delete a passkey. | ||
|
|
||
| ### Example | ||
|
|
||
| The tag is typically used inside a [`{{ user:passkeys }}`](/tags/user-passkeys) loop: | ||
|
|
||
| ::tabs | ||
|
|
||
| ::tab antlers | ||
| ```antlers | ||
| {{ user:passkeys as="passkeys" }} | ||
| {{ passkeys }} | ||
| <div> | ||
| {{ name }} | ||
|
|
||
| {{ user:delete_passkey_form :id="id" }} | ||
| <button type="submit">Delete</button> | ||
| {{ /user:delete_passkey_form }} | ||
| </div> | ||
| {{ /passkeys }} | ||
| {{ /user:passkeys }} | ||
| ``` | ||
| ::tab blade | ||
| ```blade | ||
| <s:user:passkeys as="passkeys"> | ||
| @foreach ($passkeys as $passkey) | ||
| <div> | ||
| {{ $passkey['name'] }} | ||
|
|
||
| <s:user:delete_passkey_form :id="$passkey['id']"> | ||
| <button type="submit">Delete</button> | ||
| </s:user:delete_passkey_form> | ||
| </div> | ||
| @endforeach | ||
| </s:user:passkeys> | ||
| ``` | ||
| :: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,113 @@ | ||
| --- | ||
| id: 7a958307-4cdb-47f3-a689-0c7de57e3ff7 | ||
| blueprint: tag | ||
| title: 'User:Passkey_Form' | ||
| description: 'Creates a passkey registration form' | ||
| intro: 'Allows authenticated users to set up passkeys' | ||
| variables: | ||
| - | ||
| name: create_url | ||
| type: string | ||
| description: 'URL to fetch WebAuthn attestation options for creating a new passkey.' | ||
| - | ||
| name: store_url | ||
|
duncanmcclean marked this conversation as resolved.
Outdated
|
||
| type: string | ||
| description: 'URL to store the new passkey after registration.' | ||
| - | ||
| name: errors | ||
| type: array | ||
| description: An array of validation errors. | ||
| - | ||
| name: success | ||
| type: string | ||
| description: A success message. | ||
|
duncanmcclean marked this conversation as resolved.
Outdated
|
||
| related_entries: | ||
| - 38323438-4719-4a7b-ba5a-8abfe0d7dfc0 | ||
| - d0ed4ac0-536a-47a1-965b-202b52baddb2 | ||
| - 7432f1cb-7418-4d54-8e65-51b1ae3bcb3a | ||
| --- | ||
| ## Overview | ||
|
|
||
| The `user:passkey_form` tag provides the necessary URLs to set up passkeys for authenticated users. | ||
|
|
||
| ### JavaScript helpers | ||
|
|
||
| You'll need to include the frontend helpers script on your page: | ||
|
|
||
| ```html | ||
| <script src="/vendor/statamic/frontend/js/helpers.js"></script> | ||
| ``` | ||
|
|
||
| ### Example | ||
|
|
||
| ::tabs | ||
|
|
||
| ::tab antlers | ||
| ```antlers | ||
| {{ 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 }} | ||
|
duncanmcclean marked this conversation as resolved.
Outdated
|
||
|
|
||
| <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), | ||
| // csrfToken (optional) | ||
| }); | ||
| }); | ||
| </script> | ||
| {{ /user:passkey_form }} | ||
| ``` | ||
| ::tab blade | ||
| ```blade | ||
| <s: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> | ||
| @endif | ||
|
|
||
| @if ($errors) | ||
| <ul> | ||
| @foreach ($errors as $error) | ||
| <li>{{ $error }}</li> | ||
| @endforeach | ||
| </ul> | ||
| @endif | ||
|
|
||
| <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), | ||
| // csrfToken (optional) | ||
| }); | ||
| }); | ||
| </script> | ||
| </s:user:passkey_form> | ||
| ``` | ||
| :: | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,97 @@ | ||
| --- | ||
| id: 38323438-4719-4a7b-ba5a-8abfe0d7dfc0 | ||
| blueprint: tag | ||
| title: 'User:Passkeys' | ||
| description: 'Lists the current user''s passkeys' | ||
| intro: 'Loop through the authenticated user''s registered passkeys.' | ||
| variables: | ||
| - | ||
| name: id | ||
| type: string | ||
| description: 'The passkey identifier.' | ||
| - | ||
| name: name | ||
| type: string | ||
| description: 'The user-defined passkey name.' | ||
| - | ||
| name: last_login | ||
| type: Carbon | ||
| description: 'The last time the passkey was used for login, or null if never used.' | ||
| related_entries: | ||
| - 7432f1cb-7418-4d54-8e65-51b1ae3bcb3a | ||
| - 7a958307-4cdb-47f3-a689-0c7de57e3ff7 | ||
| - d0ed4ac0-536a-47a1-965b-202b52baddb2 | ||
| --- | ||
| ## Overview | ||
|
|
||
| The `user:passkeys` tag loops through the user's passkeys. Useful for building a passkey management page where users can view and delete their passkeys. | ||
|
|
||
| ### Example | ||
|
|
||
| ::tabs | ||
|
|
||
| ::tab antlers | ||
| ```antlers | ||
| {{ 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">Delete</button> | ||
| {{ /user:delete_passkey_form }} | ||
| </li> | ||
| {{ /passkeys }} | ||
| </ul> | ||
| {{ else }} | ||
| <p>You haven't set up any passkeys yet.</p> | ||
| {{ /if }} | ||
| {{ /user:passkeys }} | ||
| ``` | ||
| ::tab blade | ||
| ```blade | ||
| <s:user:passkeys as="passkeys"> | ||
| @if ($passkeys) | ||
| <h3>Your Passkeys</h3> | ||
| <ul> | ||
| @foreach ($passkeys as $passkey) | ||
| <li> | ||
| <strong>{{ $passkey['name'] }}</strong> | ||
| @if ($passkey['last_login']) | ||
| <span>Last used: {{ $passkey['last_login']->format('M j, Y g:i A') }}</span> | ||
| @else | ||
| <span>Never used</span> | ||
| @endif | ||
|
|
||
| <s:user:delete_passkey_form :id="$passkey['id']"> | ||
| <button type="submit">Delete</button> | ||
| </s:user:delete_passkey_form> | ||
| </li> | ||
| @endforeach | ||
| </ul> | ||
| @else | ||
| <p>You haven't set up any passkeys yet.</p> | ||
| @endif | ||
| </s:user:passkeys> | ||
| ``` | ||
| :: | ||
|
|
||
| ## Aliasing | ||
|
|
||
| You can use the `as` parameter to alias the passkeys into a variable, which allows you to use `{{ if passkeys }}` to check if there are any passkeys before rendering. | ||
|
|
||
| ```antlers | ||
| {{ user:passkeys as="passkeys" }} | ||
| {{ if passkeys }} | ||
| {{# Render passkeys list #}} | ||
| {{ /if }} | ||
| {{ /user:passkeys }} | ||
| ``` |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.