[GH-ISSUE #7985] Anonymous users with attached passkeys still are anonymous. #10962

Open
opened 2026-04-13 07:21:11 -05:00 by GiteaMirror · 1 comment
Owner

Originally created by @TimoStolz on GitHub (Feb 15, 2026).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/7985

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

Background

My service deals with psychological counseling. Therefore, when sending a request, my users start with "anonymous()". They can then either save a URL and/or protect their account with a passkey to return to their message and the response later.

When anonymous accounts receive a passkey, they are still considered anonymous. They still have isAnonymous = True/1 in the database—is this intentional?

Setup

export const auth = betterAuth({
  secret,
  baseURL,
  trustedOrigins: [appOrigin, passkeyOrigin],
  database: new Database(dbPath),
  emailAndPassword: {
    enabled: true,
  },
  plugins: [
    anonymous(),
    passkey({
      origin: passkeyOrigin,
      rpID: passkeyRpId,
      rpName: passkeyRpName,
    }),
  ],
});
// First, users can send a message without entering other personal data.
await authClient.signIn.anonymous(); 

// Then, they can protect the UUID-based link with a passkey.
await authClient.passkey.addPasskey({ name: "secret-name-for-correspondence" });

When I use SQLite to check if the user still is anonymous, that's the case.

select u.* 
from passkey as k 
join user as u on (k.userId = u.id);

In the results, I see isAnonymous = 1 for all users with assigned passkeys.

Current vs. Expected behavior

When a passkey is attached, the user can come back at any later point in time. In this regard, the user could be considered a "full" user, even without further personal information. At least for our application, that would line up with the use case.

Still, the user is somehow anonymous in terms of missing personal data, right? However, it's not a throw-away-user any longer.

What version of Better Auth are you using?

1.4.18

System info

> npx auth info --json
error: unknown command 'info'
(Did you mean init?)

Which area(s) are affected? (Select all that apply)

Backend

Auth config (if applicable)

export const auth = betterAuth({
  secret,
  baseURL,
  trustedOrigins: [appOrigin, passkeyOrigin],
  database: new Database(dbPath),
  emailAndPassword: {
    enabled: true,
  },
  plugins: [
    anonymous(),
    passkey({
      origin: passkeyOrigin,
      rpID: passkeyRpId,
      rpName: passkeyRpName,
    }),
  ],
});

Additional context

No response

Originally created by @TimoStolz on GitHub (Feb 15, 2026). Original GitHub issue: https://github.com/better-auth/better-auth/issues/7985 ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce # Background My service deals with psychological counseling. Therefore, when sending a request, my users start with "anonymous()". They can then either save a URL and/or protect their account with a passkey to return to their message and the response later. When anonymous accounts receive a passkey, they are still considered anonymous. They still have `isAnonymous = True/1` in the database—is this intentional? # Setup ```ts export const auth = betterAuth({ secret, baseURL, trustedOrigins: [appOrigin, passkeyOrigin], database: new Database(dbPath), emailAndPassword: { enabled: true, }, plugins: [ anonymous(), passkey({ origin: passkeyOrigin, rpID: passkeyRpId, rpName: passkeyRpName, }), ], }); ``` ```ts // First, users can send a message without entering other personal data. await authClient.signIn.anonymous(); // Then, they can protect the UUID-based link with a passkey. await authClient.passkey.addPasskey({ name: "secret-name-for-correspondence" }); ``` When I use SQLite to check if the user still is anonymous, that's the case. ```sql select u.* from passkey as k join user as u on (k.userId = u.id); ``` In the results, I see `isAnonymous = 1` for all users with assigned passkeys. ### Current vs. Expected behavior When a passkey is attached, the user can come back at any later point in time. In this regard, the user could be considered a "full" user, even without further personal information. At least for our application, that would line up with the use case. Still, the user is somehow anonymous in terms of missing personal data, right? However, it's not a throw-away-user any longer. ### What version of Better Auth are you using? 1.4.18 ### System info ```bash > npx auth info --json error: unknown command 'info' (Did you mean init?) ``` ### Which area(s) are affected? (Select all that apply) Backend ### Auth config (if applicable) ```typescript export const auth = betterAuth({ secret, baseURL, trustedOrigins: [appOrigin, passkeyOrigin], database: new Database(dbPath), emailAndPassword: { enabled: true, }, plugins: [ anonymous(), passkey({ origin: passkeyOrigin, rpID: passkeyRpId, rpName: passkeyRpName, }), ], }); ``` ### Additional context _No response_
GiteaMirror added the credentialsbug labels 2026-04-13 07:21:11 -05:00
Author
Owner

@dosubot[bot] commented on GitHub (Feb 15, 2026):

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

This is a known issue. The isAnonymous flag not being updated when adding a passkey is related to issue #283.

Why this happens: The anonymous plugin's account linking logic only triggers during authentication paths (like /passkey/verify-authentication), not during registration paths (like /passkey/verify-registration). So when you call authClient.passkey.addPasskey(), the passkey is stored but the isAnonymous flag isn't touched.

Workaround: You can manually update the flag after adding the passkey:

await authClient.signIn.anonymous();
await authClient.passkey.addPasskey({ name: "secret-name-for-correspondence" });

// Manually mark as non-anonymous
await authClient.updateUser({
  isAnonymous: false,
} as Parameters<typeof authClient.updateUser>[0] & { isAnonymous: boolean });

Alternatively, having users sign out and sign back in with the passkey would trigger the account linking logic, but that's probably not ideal for your UX.

Your use case (anonymous → passkey-only accounts) is valid and arguably should work without the manual workaround. You might want to add a 👍 to #283 to help prioritize a fix.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other

Chat with Dosu Open in Cursor Join Discord Share on X

<!-- gh-comment-id:3905292948 --> @dosubot[bot] commented on GitHub (Feb 15, 2026): <!-- Greeting --> Hi @TimoStolz! I'm [Dosu](https://go.dosu.dev/dosubot) and I’m helping the better-auth team. <!-- Answer --> This is a known issue. The `isAnonymous` flag not being updated when adding a passkey is related to [issue #283](https://github.com/better-auth/better-auth/issues/283). **Why this happens:** The anonymous plugin's account linking logic only triggers during *authentication* paths (like `/passkey/verify-authentication`), not during *registration* paths (like `/passkey/verify-registration`). So when you call `authClient.passkey.addPasskey()`, the passkey is stored but the `isAnonymous` flag isn't touched. **Workaround:** You can manually update the flag after adding the passkey: ```typescript await authClient.signIn.anonymous(); await authClient.passkey.addPasskey({ name: "secret-name-for-correspondence" }); // Manually mark as non-anonymous await authClient.updateUser({ isAnonymous: false, } as Parameters<typeof authClient.updateUser>[0] & { isAnonymous: boolean }); ``` Alternatively, having users sign out and sign back in with the passkey would trigger the account linking logic, but that's probably not ideal for your UX. Your use case (anonymous → passkey-only accounts) is valid and arguably should work without the manual workaround. You might want to add a 👍 to [#283](https://github.com/better-auth/better-auth/issues/283) to help prioritize a fix. <!-- 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/1e517d0a-fed6-440d-9051-3a8e92e4ff1d?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/1e517d0a-fed6-440d-9051-3a8e92e4ff1d?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/1e517d0a-fed6-440d-9051-3a8e92e4ff1d?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/1e517d0a-fed6-440d-9051-3a8e92e4ff1d?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/1e517d0a-fed6-440d-9051-3a8e92e4ff1d?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/1e517d0a-fed6-440d-9051-3a8e92e4ff1d?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/1e517d0a-fed6-440d-9051-3a8e92e4ff1d?feedback_type=other)</sup> [![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Open in Cursor](https://dosu.dev/dosu-in-cursor.svg)](https://cursor.com/link/prompt?text=This%20is%20a%20known%20issue.%20The%20%60isAnonymous%60%20flag%20not%20being%20updated%20when%20adding%20a%20passkey%20is%20related%20to%20%5Bissue%20%23283%5D%28https%3A//github.com/better-auth/better-auth/issues/283%29.%0A%0A%2A%2AWhy%20this%20happens%3A%2A%2A%20The%20anonymous%20plugin%27s%20account%20linking%20logic%20only%20triggers%20during%20%2Aauthentication%2A%20paths%20%28like%20%60/passkey/verify-authentication%60%29%2C%20not%20during%20%2Aregistration%2A%20paths%20%28like%20%60/passkey/verify-registration%60%29.%20So%20when%20you%20call%20%60authClient.passkey.addPasskey%28%29%60%2C%20the%20passkey%20is%20stored%20but%20the%20%60isAnonymous%60%20flag%20isn%27t%20touched.%0A%0A%2A%2AWorkaround%3A%2A%2A%20You%20can%20manually%20update%20the%20flag%20after%20adding%20the%20passkey%3A%0A%0A%60%60%60typescript%0Aawait%20authClient.signIn.anonymous%28%29%3B%0Aawait%20authClient.passkey.addPasskey%28%7B%20name%3A%20%22secret-name-for-correspondence%22%20%7D%29%3B%0A%0A//%20Manually%20mark%20as%20non-anonymous%0Aawait%20authClient.updateUser%28%7B%0A%20%20isAnonymous%3A%20false%2C%0A%7D%20as%20Parameters%3Ctypeof%20authClient.updateUser%3E%5B0%5D%20%26%20%7B%20isAnonymous%3A%20boolean%20%7D%29%3B%0A%60%60%60%0A%0AAlternatively%2C%20having%20users%20sign%20out%20and%20sign%20back%20in%20with%20the%20passkey%20would%20trigger%20the%20account%20linking%20logic%2C%20but%20that%27s%20probably%20not%20ideal%20for%20your%20UX.%0A%0AYour%20use%20case%20%28anonymous%20%E2%86%92%20passkey-only%20accounts%29%20is%20valid%20and%20arguably%20should%20work%20without%20the%20manual%20workaround.%20You%20might%20want%20to%20add%20a%20%F0%9F%91%8D%20to%20%5B%23283%5D%28https%3A//github.com/better-auth/better-auth/issues/283%29%20to%20help%20prioritize%20a%20fix.)&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/7985)
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#10962