Skip to content

Commit 3987655

Browse files
committed
Add remember me check for passkeys
1 parent 24d0a81 commit 3987655

4 files changed

Lines changed: 47 additions & 1 deletion

File tree

composer.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

resources/js/alpine/components/passkey-login.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ Alpine.data('passkeyLogin', () => ({
44
supported: false,
55
busy: false,
66
error: '',
7+
remember: false,
78
showCreateHint: false,
89
hasAutoPrompted: false,
910

@@ -14,6 +15,7 @@ Alpine.data('passkeyLogin', () => ({
1415
// If backend already reported an invalid passkey login attempt,
1516
// immediately show the "sign in first, then create passkey" guidance.
1617
this.showCreateHint = this.$el.dataset.serverPasskeyError === '1';
18+
this.remember = this.$el.dataset.rememberDefault === '1';
1719

1820
const shouldAutoPrompt = this.$el.dataset.autoPrompt === '1';
1921
if (this.supported && shouldAutoPrompt && !this.showCreateHint) {
@@ -57,6 +59,7 @@ Alpine.data('passkeyLogin', () => ({
5759
optionsJSON: optionsJson,
5860
});
5961

62+
this.$refs.remember.value = this.remember ? '1' : '0';
6063
this.$refs.response.value = JSON.stringify(startAuthenticationResponse);
6164
document.getElementById('passkey-login-form')?.submit();
6265
} catch (error) {

resources/views/partials/passkey-authenticate.blade.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
data-options-url="{{ route('passkeys.authentication_options') }}"
55
data-server-passkey-error="{{ session('authenticatePasskey::reason') === 'invalid_passkey' ? '1' : '0' }}"
66
data-auto-prompt="{{ ($autoPromptPasskey ?? true) ? '1' : '0' }}"
7+
data-remember-default="{{ old('rememberme') ? '1' : '0' }}"
78
data-captcha-enabled="{{ \App\Support\CaptchaHelper::isEnabled() ? '1' : '0' }}"
89
data-captcha-field="{{ \App\Support\CaptchaHelper::isEnabled() ? \App\Support\CaptchaHelper::getResponseFieldName() : '' }}"
910
class="mt-6"
@@ -26,6 +27,18 @@ class="mt-6"
2627
<input type="hidden" name="g-recaptcha-response" x-ref="recaptchaResponse" value="">
2728
</form>
2829

30+
<div class="mt-4 flex items-center">
31+
<input
32+
id="passkey-remember"
33+
x-model="remember"
34+
type="checkbox"
35+
class="h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500 dark:border-gray-600 dark:text-blue-400"
36+
>
37+
<label for="passkey-remember" class="ml-2 block text-sm text-gray-700 dark:text-gray-300">
38+
Remember me
39+
</label>
40+
</div>
41+
2942
<button
3043
type="button"
3144
@click="authenticate()"

tests/Feature/Auth/PasskeyAuthenticationTest.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,36 @@ public function test_passkey_authentication_logs_user_in_and_sets_2fa_session_fl
7070
Event::assertDispatched(UserLoggedIn::class);
7171
}
7272

73+
public function test_passkey_authentication_with_remember_sets_remember_token(): void
74+
{
75+
Event::fake([UserLoggedIn::class]);
76+
$user = $this->createUser('passkey-remember@example.test');
77+
78+
$passkey = new Passkey;
79+
$passkey->setRawAttributes([
80+
'id' => 3,
81+
'authenticatable_id' => $user->id,
82+
'name' => 'Desktop',
83+
'credential_id' => 'credential-3',
84+
'data' => '{}',
85+
], true);
86+
$passkey->setRelation('authenticatable', $user);
87+
88+
FakeFindPasskeyAction::$passkey = $passkey;
89+
config()->set('passkeys.actions.find_passkey', FakeFindPasskeyAction::class);
90+
91+
$this
92+
->withSession(['passkey-authentication-options' => '{}'])
93+
->post(route('passkeys.login'), [
94+
'start_authentication_response' => json_encode(['id' => 'credential-3'], JSON_THROW_ON_ERROR),
95+
'remember' => true,
96+
])
97+
->assertRedirect('/');
98+
99+
$this->assertAuthenticatedAs($user);
100+
$this->assertNotNull($user->fresh()?->remember_token);
101+
}
102+
73103
public function test_unverified_users_cannot_authenticate_with_passkeys(): void
74104
{
75105
$user = $this->createUser('unverified@example.test', false);

0 commit comments

Comments
 (0)