[GH-ISSUE #5099] Authorised actions with passkey #18794

Closed
opened 2026-04-15 17:27:23 -05:00 by GiteaMirror · 4 comments
Owner

Originally created by @firstaxel on GitHub (Oct 5, 2025).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/5099

Does any one have a implementation of how to use better auth passkey for authenticating actions performed on a website not for signing in into the website for authenticating transactions like money transfer and the likes

Originally created by @firstaxel on GitHub (Oct 5, 2025). Original GitHub issue: https://github.com/better-auth/better-auth/issues/5099 Does any one have a implementation of how to use better auth passkey for authenticating actions performed on a website not for signing in into the website for authenticating transactions like money transfer and the likes
GiteaMirror added the lockedenhancement labels 2026-04-15 17:27:24 -05:00
Author
Owner

@dosubot[bot] commented on GitHub (Oct 5, 2025):

Hi @firstaxel! I'm Dosu and I’m helping the better-auth team.

There isn't a built-in Better Auth endpoint specifically for authorizing sensitive actions like transactions with passkey, but you can use the existing passkey authentication endpoints to implement this flow. The key endpoints are /passkey/generate-authenticate-options to generate a WebAuthn challenge and /passkey/verify-authentication to verify the user's response. These endpoints are designed to be invoked independently, so you can trigger a passkey authentication prompt right before a sensitive action (like a money transfer) to perform step-up authentication and confirm user intent. This approach is similar to how two-factor authentication is handled for step-up scenarios in Better Auth, and the plugin architecture supports integrating such flows into your transaction logic. See the implementation details for these endpoints in the passkey plugin for reference:
passkey plugin source.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other  Chat with Dosu Join Discord Share on X

<!-- gh-comment-id:3369016742 --> @dosubot[bot] commented on GitHub (Oct 5, 2025): <!-- Greeting --> Hi @firstaxel! I'm [Dosu](https://go.dosu.dev/dosubot) and I’m helping the better-auth team. <!-- Answer --> There isn't a built-in Better Auth endpoint specifically for authorizing sensitive actions like transactions with passkey, but you can use the existing passkey authentication endpoints to implement this flow. The key endpoints are `/passkey/generate-authenticate-options` to generate a WebAuthn challenge and `/passkey/verify-authentication` to verify the user's response. These endpoints are designed to be invoked independently, so you can trigger a passkey authentication prompt right before a sensitive action (like a money transfer) to perform step-up authentication and confirm user intent. This approach is similar to how two-factor authentication is handled for step-up scenarios in Better Auth, and the plugin architecture supports integrating such flows into your transaction logic. See the implementation details for these endpoints in the passkey plugin for reference: [passkey plugin source](https://github.com/better-auth/better-auth/blob/ad59590e2491359a2787d75b3209b02351ff99de/packages/better-auth/src/plugins/passkey/index.ts). <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/9e3c46ff-5ada-493d-bba1-29c382981a18?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/9e3c46ff-5ada-493d-bba1-29c382981a18?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/9e3c46ff-5ada-493d-bba1-29c382981a18?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/9e3c46ff-5ada-493d-bba1-29c382981a18?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/9e3c46ff-5ada-493d-bba1-29c382981a18?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/9e3c46ff-5ada-493d-bba1-29c382981a18?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/9e3c46ff-5ada-493d-bba1-29c382981a18?feedback_type=other)</sup>&nbsp;&nbsp;[![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/better-auth/better-auth/issues/5099)
Author
Owner

@ping-maxwell commented on GitHub (Oct 6, 2025):

We don't exactly have a function for the purpose of this, although for critical actions that require authorization before proceeding (like deleting an account) we often use session freshness (docs), it means that the logic will check if the session the user has is under a certain amount of time to which we can consider as "fresh". After it's determined that a given session is fresh we can then assume it's the actual user, so we proceed with the action.

My recommendation is to build something around this idea, unless you strictly require passkey or you don't want new sessions.

If this idea doesn't work for you, then it could be a good idea to look into how we made our passkey plugin (index.ts, client.ts) and see what you can do with some of the endpoints or logic from there, to build off of it.

<!-- gh-comment-id:3370939897 --> @ping-maxwell commented on GitHub (Oct 6, 2025): We don't exactly have a function for the purpose of this, although for critical actions that require authorization before proceeding (like deleting an account) we often use session freshness ([docs](https://www.better-auth.com/docs/concepts/session-management#session-freshness)), it means that the logic will check if the session the user has is under a certain amount of time to which we can consider as "fresh". After it's determined that a given session is fresh we can then assume it's the actual user, so we proceed with the action. My recommendation is to build something around this idea, unless you strictly require passkey or you don't want new sessions. If this idea doesn't work for you, then it could be a good idea to look into how we made our passkey plugin ([index.ts](https://github.com/better-auth/better-auth/blob/canary/packages/better-auth/src/plugins/passkey/index.ts), [client.ts](https://github.com/better-auth/better-auth/blob/canary/packages/better-auth/src/plugins/passkey/client.ts)) and see what you can do with some of the endpoints or logic from there, to build off of it.
Author
Owner

@ShivamGupta-SM commented on GitHub (Feb 19, 2026):

We ran into exactly this problem in production. Our app needs passkey re-authentication for sensitive operations (withdrawals, role changes, phone number changes) — not login.

The problem with using verifyPasskeyAuthentication for this is that it always creates a new session, even when the user already has one. We just need to verify the assertion and confirm user ownership — no session needed.

We ended up bypassing Better Auth entirely and using @simplewebauthn/server directly (the same library Better Auth uses internally). Our workaround:

  1. Custom endpoint generates a challenge and stores it in the verification table
  2. Frontend does navigator.credentials.get(options)
  3. Backend verifies the assertion via verifyAuthenticationResponse() from @simplewebauthn/server
  4. Updates the passkey counter (replay protection) and deletes the used challenge
  5. No session created — just a verified user ID

This works, but it means reimplementing half the passkey plugin (challenge management, credential lookup, counter updates, RP config) just to avoid session creation.

Filed a feature request for this: #8071

Session freshness (freshAge) isn't a substitute here — time-based freshness is weaker than cryptographic proof of user presence via biometrics. For financial operations, you need the latter.

<!-- gh-comment-id:3930630107 --> @ShivamGupta-SM commented on GitHub (Feb 19, 2026): We ran into exactly this problem in production. Our app needs passkey re-authentication for sensitive operations (withdrawals, role changes, phone number changes) — not login. The problem with using `verifyPasskeyAuthentication` for this is that it **always creates a new session**, even when the user already has one. We just need to verify the assertion and confirm user ownership — no session needed. We ended up bypassing Better Auth entirely and using `@simplewebauthn/server` directly (the same library Better Auth uses internally). Our workaround: 1. Custom endpoint generates a challenge and stores it in the `verification` table 2. Frontend does `navigator.credentials.get(options)` 3. Backend verifies the assertion via `verifyAuthenticationResponse()` from `@simplewebauthn/server` 4. Updates the passkey counter (replay protection) and deletes the used challenge 5. **No session created** — just a verified user ID This works, but it means reimplementing half the passkey plugin (challenge management, credential lookup, counter updates, RP config) just to avoid session creation. Filed a feature request for this: #8071 Session freshness (`freshAge`) isn't a substitute here — time-based freshness is weaker than cryptographic proof of user presence via biometrics. For financial operations, you need the latter.
Author
Owner

@github-actions[bot] commented on GitHub (Apr 1, 2026):

This issue has been locked as it was closed more than 7 days ago. If you're experiencing a similar problem or you have additional context, please open a new issue and reference this one.

<!-- gh-comment-id:4166557728 --> @github-actions[bot] commented on GitHub (Apr 1, 2026): This issue has been locked as it was closed more than 7 days ago. If you're experiencing a similar problem or you have additional context, please open a new issue and reference this one.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#18794