{"_id":"@laravel/passkeys","_rev":"4-5902a115104e82b5d3b1090ece3d4bb1","name":"@laravel/passkeys","dist-tags":{"latest":"0.4.0"},"versions":{"0.0.1":{"name":"@laravel/passkeys","version":"0.0.1","keywords":["laravel","passkeys","webauthn","authentication","passwordless"],"author":{"name":"Laravel"},"license":"MIT","_id":"@laravel/passkeys@0.0.1","maintainers":[{"name":"taylorotwell","email":"taylor@laravel.com"},{"name":"olivernybroe","email":"oliver@laravel.com"},{"name":"joetannenbaum","email":"joe@joe.codes"}],"homepage":"https://github.com/laravel/passkeys#readme","bugs":{"url":"https://github.com/laravel/passkeys/issues"},"dist":{"shasum":"77f3af3d01eac0a4117c5631d0f8563f6dba5c15","tarball":"https://registry.npmjs.org/@laravel/passkeys/-/passkeys-0.0.1.tgz","fileCount":20,"integrity":"sha512-J47W/UZ343qXP1VCieg6hzSfaKLB72XRZfHSR0E9n6u5ZgyB9GzBeNd2OhZ0RnRsTO/3FV/92NGx+iemREnh2w==","signatures":[{"sig":"MEUCIQCYlXkYqJ7O0cMAog0l0h4kcgqiNVngb3qRNc89sut7IAIgUVJEWNNY+/TO8EqPp8n/wjxkIQ7J9xOiS/Cup7IwZDM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":32564},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=20.19.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./vue":{"types":"./dist/vue.d.ts","import":"./dist/vue.js"},"./react":{"types":"./dist/react.d.ts","import":"./dist/react.js"},"./svelte":{"types":"./dist/svelte.d.ts","import":"./dist/svelte.js"}},"gitHead":"2d2e574a298576d16905f7083754acf422099a7a","scripts":{"dev":"vite build --watch","lint":"eslint","test":"vitest","build":"vite build","clean":"rm -rf dist","format":"prettier --write .","prepare":"npm run build","typecheck":"tsc --noEmit","prepublishOnly":"npm run lint && npm run typecheck && npm test -- --run"},"_npmUser":{"name":"joetannenbaum","email":"joe@joe.codes"},"repository":{"url":"git+https://github.com/laravel/passkeys.git","type":"git"},"_npmVersion":"10.9.3","description":"Passkeys client for Laravel applications","directories":{},"_nodeVersion":"22.20.0","dependencies":{"@simplewebauthn/browser":"^13.0.0"},"_hasShrinkwrap":false,"devDependencies":{"vue":"^3.0.0","vite":"^7.0.0","jsdom":"^28.0.0","react":"^18.2.0","eslint":"^10.0.0","svelte":"^5.0.0","vitest":"^3.0.0","prettier":"^3.5.0","happy-dom":"^15.0.0","react-dom":"^18.2.0","typescript":"^5.3.0","@types/react":"^18.2.0 || ^19.0.0","@vue/test-utils":"^2.4.0","vite-plugin-dts":"^4.5.0","@testing-library/react":"^16.0.0","@testing-library/svelte":"^5.0.0","@typescript-eslint/parser":"^8.0.0","@sveltejs/vite-plugin-svelte":"^6.0.0","@typescript-eslint/eslint-plugin":"^8.0.0"},"peerDependencies":{"vue":"^3.0.0","react":"^18.0.0 || ^19.0.0","svelte":"^5.0.0"},"peerDependenciesMeta":{"vue":{"optional":true},"react":{"optional":true},"svelte":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/passkeys_0.0.1_1776876057441_0.21188742301854435","host":"s3://npm-registry-packages-npm-production"}},"0.1.0":{"name":"@laravel/passkeys","version":"0.1.0","keywords":["laravel","passkeys","webauthn","authentication","passwordless"],"author":{"name":"Laravel"},"license":"MIT","_id":"@laravel/passkeys@0.1.0","maintainers":[{"name":"taylorotwell","email":"taylor@laravel.com"},{"name":"olivernybroe","email":"oliver@laravel.com"},{"name":"joetannenbaum","email":"joe@joe.codes"}],"homepage":"https://github.com/laravel/passkeys#readme","bugs":{"url":"https://github.com/laravel/passkeys/issues"},"dist":{"shasum":"eee69fafd0adadfcd338b50db4004d83dd902c90","tarball":"https://registry.npmjs.org/@laravel/passkeys/-/passkeys-0.1.0.tgz","fileCount":20,"integrity":"sha512-a5tEuiGDPjR/abDIOYm+Np2ThK3uBHRtDnaL5PdEAxoWcJ+f9lJnnZethNqVr9cBecgQndOvElSyhI06uWHYSA==","signatures":[{"sig":"MEUCIG/nrtAiP7/PrEJ2B5buVvO8hnV+6We6IFMjVMIKaIq/AiEAnvI+zJzUnfhWVmvWwZ+zXh0qdWOOViGgA9eFA4L5884=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@laravel%2fpasskeys@0.1.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":32564},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=20.19.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./vue":{"types":"./dist/vue.d.ts","import":"./dist/vue.js"},"./react":{"types":"./dist/react.d.ts","import":"./dist/react.js"},"./svelte":{"types":"./dist/svelte.d.ts","import":"./dist/svelte.js"}},"gitHead":"caf20de925587fe0024435a1c9b188a7e5e1688f","scripts":{"dev":"vite build --watch","lint":"eslint","test":"vitest","build":"vite build","clean":"rm -rf dist","format":"prettier --write .","prepare":"npm run build","typecheck":"tsc --noEmit","prepublishOnly":"npm run lint && npm run typecheck && npm test -- --run"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:a0e056b9-2b62-4f65-8103-8111f1db6134"}},"repository":{"url":"git+https://github.com/laravel/passkeys.git","type":"git"},"_npmVersion":"11.12.1","description":"Passkeys client for Laravel applications","directories":{},"_nodeVersion":"20.20.2","dependencies":{"@simplewebauthn/browser":"^13.0.0"},"_hasShrinkwrap":false,"devDependencies":{"vue":"^3.0.0","vite":"^7.0.0","jsdom":"^28.0.0","react":"^18.2.0","eslint":"^10.0.0","svelte":"^5.0.0","vitest":"^3.0.0","prettier":"^3.5.0","happy-dom":"^15.0.0","react-dom":"^18.2.0","typescript":"^5.3.0","@types/react":"^18.2.0 || ^19.0.0","@vue/test-utils":"^2.4.0","vite-plugin-dts":"^4.5.0","@testing-library/react":"^16.0.0","@testing-library/svelte":"^5.0.0","@typescript-eslint/parser":"^8.0.0","@sveltejs/vite-plugin-svelte":"^6.0.0","@typescript-eslint/eslint-plugin":"^8.0.0"},"peerDependencies":{"vue":"^3.0.0","react":"^18.0.0 || ^19.0.0","svelte":"^5.0.0"},"peerDependenciesMeta":{"vue":{"optional":true},"react":{"optional":true},"svelte":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/passkeys_0.1.0_1776876542601_0.7524659116013375","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@laravel/passkeys","version":"0.2.0","keywords":["laravel","passkeys","webauthn","authentication","passwordless"],"author":{"name":"Laravel"},"license":"MIT","_id":"@laravel/passkeys@0.2.0","maintainers":[{"name":"taylorotwell","email":"taylor@laravel.com"},{"name":"olivernybroe","email":"oliver@laravel.com"},{"name":"joetannenbaum","email":"joe@joe.codes"}],"homepage":"https://github.com/laravel/passkeys#readme","bugs":{"url":"https://github.com/laravel/passkeys/issues"},"dist":{"shasum":"326b05e06403ea0e6efc6f5a79c21c8aafab090c","tarball":"https://registry.npmjs.org/@laravel/passkeys/-/passkeys-0.2.0.tgz","fileCount":20,"integrity":"sha512-K+owv26weKrYaoTJutqU40UsJZpwYkqB9jdlz5Bv/C54nxj2+Py9jbVwxASWg21fLsPhn3ngPKZE5RnfakCQKg==","signatures":[{"sig":"MEQCIEfVYcu3GkH3+lLDWWhuCGvsJYeIN/X/Rl8Rdt5xhkx/AiBsw45RY7qrl8oG6ZmIdu92emjiup0y7AmQnnjfeWqQyQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@laravel%2fpasskeys@0.2.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":34782},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=20.19.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./vue":{"types":"./dist/vue.d.ts","import":"./dist/vue.js"},"./react":{"types":"./dist/react.d.ts","import":"./dist/react.js"},"./svelte":{"types":"./dist/svelte.d.ts","import":"./dist/svelte.js"}},"gitHead":"c76a758bd4a72360fc72de053f7146158cd57d4b","scripts":{"dev":"vite build --watch","lint":"eslint","test":"vitest","build":"vite build","clean":"rm -rf dist","format":"prettier --write .","prepare":"npm run build","typecheck":"tsc --noEmit","prepublishOnly":"npm run lint && npm run typecheck && npm test -- --run"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:a0e056b9-2b62-4f65-8103-8111f1db6134"}},"repository":{"url":"git+https://github.com/laravel/passkeys.git","type":"git"},"_npmVersion":"11.14.1","description":"Passkeys client for Laravel applications","directories":{},"_nodeVersion":"20.20.2","dependencies":{"@simplewebauthn/browser":"^13.0.0"},"_hasShrinkwrap":false,"devDependencies":{"vue":"^3.0.0","vite":"^7.0.0","jsdom":"^28.0.0","react":"^18.2.0","eslint":"^10.0.0","svelte":"^5.0.0","vitest":"^3.0.0","prettier":"^3.5.0","happy-dom":"^15.0.0","react-dom":"^18.2.0","typescript":"^5.3.0","@types/react":"^18.2.0 || ^19.0.0","@vue/test-utils":"^2.4.0","vite-plugin-dts":"^4.5.0","@testing-library/react":"^16.0.0","@testing-library/svelte":"^5.0.0","@typescript-eslint/parser":"^8.0.0","@sveltejs/vite-plugin-svelte":"^6.0.0","@typescript-eslint/eslint-plugin":"^8.0.0"},"peerDependencies":{"vue":"^3.0.0","react":"^18.0.0 || ^19.0.0","svelte":"^5.0.0"},"peerDependenciesMeta":{"vue":{"optional":true},"react":{"optional":true},"svelte":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/passkeys_0.2.0_1778856690773_0.7029316988501446","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"@laravel/passkeys","version":"0.4.0","description":"Passkeys client for Laravel applications","keywords":["laravel","passkeys","webauthn","authentication","passwordless"],"homepage":"https://github.com/laravel/passkeys#readme","repository":{"type":"git","url":"git+https://github.com/laravel/passkeys.git"},"bugs":{"url":"https://github.com/laravel/passkeys/issues"},"license":"MIT","author":{"name":"Laravel"},"type":"module","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./react":{"types":"./dist/react.d.ts","import":"./dist/react.js"},"./vue":{"types":"./dist/vue.d.ts","import":"./dist/vue.js"},"./svelte":{"types":"./dist/svelte.d.ts","import":"./dist/svelte.js"}},"main":"./dist/index.js","module":"./dist/index.js","types":"./dist/index.d.ts","scripts":{"prepare":"npm run build","prepublishOnly":"npm run lint && npm run typecheck && npm test -- --run","build":"vite build","dev":"vite build --watch","test":"vitest","lint":"eslint","format":"prettier --write .","typecheck":"tsc --noEmit","clean":"rm -rf dist"},"dependencies":{"@simplewebauthn/browser":"^13.0.0"},"peerDependencies":{"react":"^18.0.0 || ^19.0.0","vue":"^3.3.0","svelte":"^5.0.0"},"peerDependenciesMeta":{"react":{"optional":true},"svelte":{"optional":true},"vue":{"optional":true}},"devDependencies":{"@testing-library/react":"^16.0.0","@testing-library/svelte":"^5.0.0","@types/react":"^18.2.0 || ^19.0.0","@typescript-eslint/eslint-plugin":"^8.0.0","@typescript-eslint/parser":"^8.0.0","eslint":"^10.0.0","happy-dom":"^15.0.0","jsdom":"^28.0.0","prettier":"^3.5.0","svelte":"^5.0.0","typescript":"^5.3.0","vite":"^7.0.0","vite-plugin-dts":"^4.5.0","vitest":"^3.0.0","vue":"^3.3.0","@vue/test-utils":"^2.4.0","@sveltejs/vite-plugin-svelte":"^6.0.0","react":"^18.2.0","react-dom":"^18.2.0"},"engines":{"node":">=20.19.0"},"gitHead":"782d723f78e92421bc5a621d6b61570c030c45ce","_id":"@laravel/passkeys@0.4.0","_nodeVersion":"24.19.0","_npmVersion":"12.0.2","dist":{"integrity":"sha512-59UHJHZPrIT8f5hFQJUR1EXhazWZTg3DcJefxSfA3aRj6xu40I/lYDveUY4oL2/h/crq9jjptSKykZDDold7aA==","shasum":"e65135f6f710dae391aabaa95681495d809aef7a","tarball":"https://registry.npmjs.org/@laravel/passkeys/-/passkeys-0.4.0.tgz","fileCount":21,"unpackedSize":37081,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@laravel%2fpasskeys@0.4.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIGfu/6rvqRDbqNpnDbYCQYYFOd0Stuvm1o4kStMRM+XJAiEArV2NAuoG2+7Qqdw2Jm/Jcr+xaLwY/dCDvTRfbOKyPMs="}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:a0e056b9-2b62-4f65-8103-8111f1db6134"}},"directories":{},"maintainers":[{"name":"taylorotwell","email":"taylor@laravel.com"},{"name":"olivernybroe","email":"oliver@laravel.com"},{"name":"joetannenbaum","email":"joe@joe.codes"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/passkeys_0.4.0_1786569417385_0.18400388324182249"},"_hasShrinkwrap":false}},"time":{"created":"2026-04-22T16:40:57.294Z","modified":"2026-08-12T21:16:57.889Z","0.0.1":"2026-04-22T16:40:57.585Z","0.1.0":"2026-04-22T16:49:02.756Z","0.2.0":"2026-05-15T14:51:30.903Z","0.4.0":"2026-08-12T21:16:57.514Z"},"bugs":{"url":"https://github.com/laravel/passkeys/issues"},"author":{"name":"Laravel"},"license":"MIT","homepage":"https://github.com/laravel/passkeys#readme","keywords":["laravel","passkeys","webauthn","authentication","passwordless"],"repository":{"type":"git","url":"git+https://github.com/laravel/passkeys.git"},"description":"Passkeys client for Laravel applications","maintainers":[{"name":"taylorotwell","email":"taylor@laravel.com"},{"name":"olivernybroe","email":"oliver@laravel.com"},{"name":"joetannenbaum","email":"joe@joe.codes"}],"readme":"# @laravel/passkeys\n\nA JavaScript client for passkey authentication designed to work with Laravel applications. It provides a fluent API for browser-side WebAuthn ceremonies (registration and authentication).\n\n## Installation\n\n```bash\nnpm install @laravel/passkeys\n```\n\n## Quick Start\n\n```js\nimport { Passkeys } from \"@laravel/passkeys\";\n\n// Register a new passkey (authenticated user)\nawait Passkeys.register({ name: \"MacBook Pro\" });\n\n// Verify passkey\nawait Passkeys.verify();\n\n// Verify and persist the login\nawait Passkeys.verify({ remember: true });\n```\n\n## Framework Helpers\n\n### React\n\n```jsx\nimport { useState } from \"react\";\nimport { usePasskeyVerify, usePasskeyRegister } from \"@laravel/passkeys/react\";\n\n// Login\nfunction LoginPage() {\n    const { verify, isLoading, error, isSupported } = usePasskeyVerify({\n        autofill: true,\n        onSuccess: (response) => {\n            if (response.redirect) {\n                window.location.href = response.redirect;\n            }\n        },\n    });\n\n    return (\n        <div>\n            {/* Add webauthn and set autofill: true to show passkeys in the input */}\n            <input type=\"text\" autoComplete=\"email webauthn\" />\n\n            <button onClick={verify} disabled={!isSupported || isLoading}>\n                {isLoading ? \"Authenticating...\" : \"Sign in with passkey\"}\n            </button>\n            {error && <p className=\"error\">{error}</p>}\n        </div>\n    );\n}\n\n// Register\nfunction RegisterForm() {\n    const [name, setName] = useState(\"\");\n    const { register, isLoading, error } = usePasskeyRegister();\n\n    return (\n        <div>\n            <input\n                value={name}\n                onChange={(e) => setName(e.target.value)}\n                placeholder=\"Passkey name\"\n            />\n            <button\n                onClick={() => register(name)}\n                disabled={isLoading || !name}\n            >\n                {isLoading ? \"Registering...\" : \"Add passkey\"}\n            </button>\n            {error && <p className=\"error\">{error}</p>}\n        </div>\n    );\n}\n```\n\n### Vue\n\n```vue\n<script setup>\nimport { ref } from \"vue\";\nimport { usePasskeyVerify, usePasskeyRegister } from \"@laravel/passkeys/vue\";\nimport { router } from \"@inertiajs/vue3\";\n\n// Login\nconst {\n    verify,\n    isLoading: verifyLoading,\n    error: verifyError,\n} = usePasskeyVerify({\n    autofill: true,\n    onSuccess: (response) => {\n        if (response.redirect) {\n            router.visit(response.redirect);\n        }\n    },\n});\n\n// Register\nconst name = ref(\"\");\nconst {\n    register,\n    isLoading: registerLoading,\n    error: registerError,\n} = usePasskeyRegister();\n</script>\n\n<template>\n    <!-- Include webauthn and set autofill: true to show passkeys in the input -->\n    <input type=\"text\" autocomplete=\"email webauthn\" />\n\n    <button @click=\"verify\" :disabled=\"verifyLoading\">\n        {{ verifyLoading ? \"Authenticating...\" : \"Sign in with passkey\" }}\n    </button>\n    <p v-if=\"verifyError\" class=\"error\">{{ verifyError }}</p>\n\n    <!-- Register -->\n    <input v-model=\"name\" placeholder=\"Passkey name\" />\n    <button @click=\"register(name)\" :disabled=\"registerLoading || !name\">\n        {{ registerLoading ? \"Registering...\" : \"Add passkey\" }}\n    </button>\n    <p v-if=\"registerError\" class=\"error\">{{ registerError }}</p>\n</template>\n```\n\n### Svelte\n\nAccess the returned values through the hook object (don't destructure), so Svelte's reactivity stays live:\n\n```svelte\n<script>\n    import { usePasskeyVerify, usePasskeyRegister } from \"@laravel/passkeys/svelte\";\n\n    const verify = usePasskeyVerify({\n        autofill: true,\n        onSuccess: (response) => {\n            if (response.redirect) window.location.href = response.redirect;\n        },\n    });\n\n    const register = usePasskeyRegister();\n    let name = $state(\"\");\n</script>\n\n<!-- Include webauthn and set autofill: true to show passkeys in the input -->\n<input type=\"email\" autocomplete=\"email webauthn\" />\n\n<button onclick={verify.verify} disabled={!verify.isSupported || verify.isLoading}>\n    {verify.isLoading ? \"Authenticating...\" : \"Sign in with passkey\"}\n</button>\n{#if verify.error}<p class=\"error\">{verify.error}</p>{/if}\n\n<input bind:value={name} placeholder=\"Passkey name\" />\n<button\n    onclick={() => register.register(name)}\n    disabled={register.isLoading || !name}\n>\n    {register.isLoading ? \"Registering...\" : \"Add passkey\"}\n</button>\n{#if register.error}<p class=\"error\">{register.error}</p>{/if}\n```\n\n## Server-Side Rendering\n\nWebAuthn is a browser-only API. The framework hooks are SSR-safe: on the server and during hydration, `isSupported` renders as `false`, then updates to the real value after the component mounts. This avoids hydration warnings without any user-visible flash — in Vue and Svelte the post-mount update runs as a microtask before the browser paints; in React it's handled by `useSyncExternalStore` (client-only apps see the real value on the first render).\n\nIf you need the synchronous value outside a component lifecycle, call `Passkeys.isSupported()` directly — it returns `false` under Node without throwing.\n\n## Passkey Autofill\n\nWhen `autofill: true` is passed, the hook asks the browser to surface saved passkeys inside the native credential-picker dropdown. The browser attaches that dropdown to an `<input>` whose `autocomplete` attribute includes the `webauthn` token (typically alongside `username` or `email`). If no such input is mounted by the time the autofill request starts, the dropdown has nowhere to anchor and silently shows nothing — no error, no console warning, just no picker.\n\nIf the browser doesn't support autofill (checked via `isAutofillSupported()`) or the user dismisses the picker, the hook falls back to doing nothing and your explicit \"Sign in with passkey\" button still works.\n\n## Core API\n\n### Public Methods\n\n| Method                             | Description                                       |\n| ---------------------------------- | ------------------------------------------------- |\n| `configure(options)`               | Configure the passkeys client                     |\n| `isSupported()`                    | Check if the browser supports passkeys            |\n| `isAutofillSupported()`            | Check if the browser supports passkey autofill    |\n| `register({ name, routes? })`      | Register a new passkey for the authenticated user |\n| `verify({ remember?, routes? })`   | Verify a passkey                                  |\n| `autofill({ remember?, routes? })` | Enable passkey autofill on the current page       |\n| `cancel()`                         | Cancel any pending passkey operation              |\n\n### Client Configuration\n\nUse `configure()` to adjust the fetch options used for passkey requests:\n\n```js\nPasskeys.configure({\n    fetch: {\n        credentials: \"include\",\n        headers: {\n            \"X-Tenant\": tenantId,\n        },\n    },\n});\n```\n\n## Expected Endpoints\n\nThis package handles communication with your Laravel application and expects the following endpoints:\n\n### Authentication (Guest)\n\n| Method | Route                     | Purpose                            |\n| ------ | ------------------------- | ---------------------------------- |\n| `GET`  | `/passkeys/login/options` | Fetch authentication options       |\n| `POST` | `/passkeys/login`         | Verify credential and authenticate |\n\n### Registration (Authenticated)\n\n| Method | Route                    | Purpose                    |\n| ------ | ------------------------ | -------------------------- |\n| `GET`  | `/user/passkeys/options` | Fetch registration options |\n| `POST` | `/user/passkeys`         | Store new passkey          |\n\n### Per-Call Route Overrides\n\n```js\nawait Passkeys.register({\n    name: \"MacBook Pro\",\n    routes: {\n        options: \"/user/security/passkeys/options\",\n        submit: \"/user/security/passkeys\",\n    },\n});\n\nawait Passkeys.verify({\n    routes: {\n        options: \"/passkeys/confirm/options\",\n        submit: \"/passkeys/confirm\",\n    },\n});\n```\n\n`register()`, `verify()`, and `autofill()` all support route overrides:\n\n```ts\ntype RouteOverrides = {\n    routes?: {\n        options?: string;\n        submit?: string;\n    };\n};\n```\n\n### Remember Me\n\nPass `remember: true` when verifying to keep the user logged in. The flag is\nalways sent with the login request and defaults to `false`:\n\n```js\nawait Passkeys.verify({ remember: true });\n```\n\n`remember` can also be a function. It is called when the login request is\nsent, after the passkey ceremony completes, so it can read the current state\nof a \"Remember me\" checkbox. This matters for autofill because the ceremony\nstarts on page load before the user picks a credential.\n\n```js\nawait Passkeys.autofill({\n    remember: () => document.querySelector(\"#remember\").checked,\n});\n```\n\nThe framework adapters accept `remember` too, and apply it to both verify and\nautofill:\n\n```jsx\n// React: a value or a getter\nconst [rememberMe, setRememberMe] = useState(false);\n\nusePasskeyVerify({ autofill: true, remember: rememberMe });\n```\n\n```js\n// Vue: a value, a ref, or a getter\nconst rememberMe = ref(false);\n\nusePasskeyVerify({ autofill: true, remember: rememberMe });\n```\n\n```js\n// Svelte: pass a getter so $state stays live\nlet rememberMe = $state(false);\n\nusePasskeyVerify({ autofill: true, remember: () => rememberMe });\n```\n\n### React / Vue / Svelte Route Overrides\n\nThe `usePasskeyVerify` adapters accept:\n\n```js\nusePasskeyVerify({\n    autofill: true,\n    routes: {\n        options: \"/passkeys/confirm/options\",\n        submit: \"/passkeys/confirm\",\n    },\n    onSuccess: (response) => {\n        if (response.redirect) {\n            window.location.href = response.redirect;\n        }\n    },\n});\n```\n\nThe `usePasskeyRegister` adapters accept:\n\n```js\nusePasskeyRegister({\n    routes: {\n        options: \"/user/security/passkeys/options\",\n        submit: \"/user/security/passkeys\",\n    },\n    onSuccess: () => {\n        window.location.reload();\n    },\n});\n```\n\n## Typed Errors\n\nAll ceremony failures are converted to `PasskeyError` subclasses so you can branch on error type:\n\n| Class                | Thrown when                                                  |\n| -------------------- | ------------------------------------------------------------ |\n| `NotSupportedError`  | The browser does not support WebAuthn                        |\n| `UserCancelledError` | The user dismissed the native prompt                         |\n| `PasskeyExistsError` | A passkey for this account/device is already registered      |\n| `InvalidDomainError` | Passkeys are used from an invalid domain                     |\n| `PasskeyError`       | Base class; used for server errors and any unmapped failures |\n\n`Passkeys.register()` and `Passkeys.verify()` throw these directly. The framework adapters expose them two ways: the `onError` callback receives the typed instance, and each hook returns an `errorInstance` field (alongside the string `error`) so you can branch from markup:\n\n```jsx\nimport { PasskeyExistsError } from \"@laravel/passkeys\";\nimport { usePasskeyRegister } from \"@laravel/passkeys/react\";\n\nconst { register, error, errorInstance } = usePasskeyRegister();\n\n// ...\n{\n    errorInstance instanceof PasskeyExistsError ? (\n        <p>You already registered a passkey on this device.</p>\n    ) : error ? (\n        <p className=\"error\">{error}</p>\n    ) : null;\n}\n```\n\n## Type Compatibility\n\nThis package uses TypeScript types from [`@simplewebauthn/browser`](https://www.npmjs.com/package/@simplewebauthn/browser). These types are fully compatible with the JSON output from the [`web-auth/webauthn-lib`](https://packagist.org/packages/web-auth/webauthn-lib) PHP package.\n\n## Package Exports\n\n| Entry Point                | Exports                                  |\n| -------------------------- | ---------------------------------------- |\n| `@laravel/passkeys`        | `Passkeys`                               |\n| `@laravel/passkeys/react`  | `usePasskeyVerify`, `usePasskeyRegister` |\n| `@laravel/passkeys/vue`    | `usePasskeyVerify`, `usePasskeyRegister` |\n| `@laravel/passkeys/svelte` | `usePasskeyVerify`, `usePasskeyRegister` |\n","readmeFilename":"README.md"}