Skip to content

fix(passkey01): ask for one name, and say it is only a label - #198

Merged
NiKrause merged 2 commits into
passkey01from
fix/passkey01-name-is-a-label
Aug 17, 2026
Merged

fix(passkey01): ask for one name, and say it is only a label#198
NiKrause merged 2 commits into
passkey01from
fix/passkey01-name-is-a-label

Conversation

@NiKrause

@NiKrause NiKrause commented Aug 16, 2026

Copy link
Copy Markdown
Owner

Ready. The provider release this waited on has landed: orbitdb-identity-provider-webauthn-did#46 merged 2026-08-16 20:04 UTC and shipped as 0.5.1 at 21:17 UTC. This branch was still pinning 0.5.0 — the version without the fix — so passkey01 has been merged in and the pin is now 0.5.1 in both package.json and the lockfile. The published package confirms it: the handle the authenticator files the credential under is generated, not derived from the typed name.

Verified locally against 0.5.1: passkey-identity.spec.js passes — both browsers use the same label and still get two distinct DIDs, which is the collision this PR is about.

The onboarding form asked for a user id (e.g. alice@example.com) and a separate display name. Both are labels — WebAuthn's user.name and displayName exist so the passkey picker has something to show — but the first read like an identifier, and until now it was one: the provider derived the WebAuthn user handle from it, and an authenticator keeps one credential per (origin, handle). Two people typing the same name on one device replaced each other's passkey, DID and all.

What changes

  • One field (data-testid="passkey-label") instead of two, with a hint that says what it is: "Only a label for the passkey picker. Your identity comes from the key, not from this name — two people on this device may use the same one."
  • No e-mail in the placeholder. user.name is still stored in the authenticator and shown in the picker, so a personal address stays a poor default even though it is no longer destructive.
  • "Create a passkey" says what a second press does when a passkey already exists: it adds an identity rather than quietly replacing one. That is new behaviour and worth naming on the screen it happens on.
  • README gains a short section on why the name is only a label, with the history that made it worth saying.

The E2E is the point

passkey-identity.spec.js now gives both browsers the same label and expects two distinct DIDs. That is the regression test at app level: before the handle became random, the suite only passed because it worked around the collision with alice-${runId}@example.com.

Verification

Build succeeds, 45 unit tests pass. passkey-identity.spec.js now runs and passes locally against the released 0.5.1. The files prettier still flags (README.md, +page.svelte, passkey-identity.spec.js) were already unformatted on passkey01 before this change; PasskeyOnboarding.svelte is clean.

The onboarding form asked for a "user id (e.g. alice@example.com)" and a
separate display name. Both are labels — WebAuthn's `user.name` and
`displayName` exist so the passkey picker has something to show — but the
first one read like an identifier, and until recently it was one: the
identity provider derived the WebAuthn user handle from it, and an
authenticator keeps one credential per (origin, handle). Two people typing
the same name on one device therefore replaced each other's passkey, DID
and all.

The provider now generates a random handle
(Le-Space/orbitdb-identity-provider-webauthn-did#45), so the text is finally
just a label. One field, said plainly in a hint below it, and the placeholder
stops inviting an e-mail address — `user.name` is still stored in the
authenticator and shown in the picker, so a personal address remains a poor
default even though it is no longer destructive.

The create option now says what a second registration does, since repeating
it adds a passkey rather than quietly replacing one.

The E2E deliberately gives both browsers the same label. That is the
regression test at app level: same typed name, two DIDs. Before the handle
became random the run only passed because it worked around the collision
with `alice-${runId}@example.com`.

Verified: build succeeds, 45 unit tests pass. E2E needs the virtual
authenticator and the released provider, so it was not run locally.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
NiKrause added a commit that referenced this pull request Aug 16, 2026
A patch release, and nothing in it forces a coordinated move: credentials
registered under 0.5.0 keep working and the derived did:key is unchanged.

What it brings this chapter is the random WebAuthn user handle
(Le-Space/orbitdb-identity-provider-webauthn-did#45). Until now the handle
was the UTF-8 of the typed user id, and an authenticator keeps one credential
per (origin, handle) — so two people registering under the same name on one
device destroyed each other's passkey and DID. The onboarding form that still
invites that (#198) can land once this is in.

Also in 0.5.1: largeBlob keystores actually persist their secret key, and the
credential now carries the authenticator's own answer on extension support
rather than the browser's guess.

Bumped in all three tracked places plus the untracked pnpm-workspace.yaml,
which is what a local pnpm 10/11 run actually reads.

Note on the lockfile: generated with pnpm 11.15.1. Running pnpm 10 here
re-resolved floating ranges across babel, metro and eslint — 552 lines of
churn for a one-package bump. The 28 lines in this diff are the provider and
its logger dependency, nothing else.

Verified: build succeeds, 45 unit tests pass, the installed provider resolves
to 0.5.1.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
@NiKrause
NiKrause marked this pull request as ready for review August 17, 2026 11:31
@NiKrause
NiKrause merged commit a44a59f into passkey01 Aug 17, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant