feat(settings): add passkey rename ui#20850
Conversation
f8e9e88 to
3b6a1a4
Compare
There was a problem hiding this comment.
Pull request overview
Adds end-to-end support for renaming passkeys from the Settings UI, including client/server auth changes and new telemetry, so users can give passkeys meaningful names without an MFA step-up.
Changes:
- Adds an inline “rename” trigger + modal with client-side validation and UX error handling for passkey names.
- Switches the auth-server passkey rename route from MFA JWT to verified session token auth; updates auth-client/settings Account usage accordingly.
- Introduces new Glean metrics + bindings and localized strings for rename flows; adds icon asset for the edit affordance.
Reviewed changes
Copilot reviewed 17 out of 18 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/fxa-shared/metrics/glean/web/index.ts | Adds generated event-name mappings for passkey rename telemetry. |
| packages/fxa-shared/metrics/glean/web/accountPref.ts | Adds generated Glean event metric types for rename view/success/error. |
| packages/fxa-shared/metrics/glean/fxa-ui-metrics.yaml | Declares new account_pref passkey rename events and extras. |
| packages/fxa-settings/src/models/Account.ts | Updates renamePasskey to use verified session token instead of MFA JWT. |
| packages/fxa-settings/src/models/Account.test.ts | Adds unit tests for Account.renamePasskey session-token usage and refresh behavior. |
| packages/fxa-settings/src/lib/types.ts | Removes the now-unused MfaReason.renamePasskey. |
| packages/fxa-settings/src/lib/glean/index.ts | Wires new passkey rename events into the settings-side Glean recorder. |
| packages/fxa-settings/src/lib/glean/index.test.ts | Adds tests ensuring rename events are recorded with expected names/extras. |
| packages/fxa-settings/src/constants/index.tsx | Adds display-safe unicode regex that permits non-BMP characters (emoji). |
| packages/fxa-settings/src/components/Settings/SubRow/index.tsx | Adds inline rename control + rename modal + shared validation helper. |
| packages/fxa-settings/src/components/Settings/SubRow/index.test.tsx | Adds component tests for rename modal behavior, validation, and telemetry calls. |
| packages/fxa-settings/src/components/Settings/SubRow/index.stories.tsx | Updates story to support rename behavior and exercise duplicate-name validation. |
| packages/fxa-settings/src/components/Settings/SubRow/en.ftl | Adds localized strings for rename UI, validation messages, and outcomes. |
| packages/fxa-settings/src/components/Icons/index.tsx | Exports a new pencil/edit icon component. |
| packages/fxa-settings/src/components/Icons/icon_pencil.min.svg | Adds the pencil SVG asset. |
| packages/fxa-settings/src/components/Icons/en.ftl | Adds the icon aria-label string for the edit icon. |
| packages/fxa-auth-server/lib/routes/passkeys.ts | Changes PATCH /passkey/{credentialId} auth to verified session token strategies. |
| packages/fxa-auth-client/lib/client.ts | Adds sessionPatch helper and updates renamePasskey to use session token auth. |
Comments suppressed due to low confidence (1)
packages/fxa-auth-server/lib/routes/passkeys.ts:996
- The rename route validates
nameonly by length, but the UI now enforces display-safe unicode (including non-BMP). To keep server-side validation authoritative (and consistent with other user-visible name fields like devices), add the same regex validation to the route payload schema.
pre: [{ method: passkeysEnabledCheck }],
auth: {
strategies: ['verifiedSessionTokenBearer', 'verifiedSessionToken'],
payload: false,
},
validate: {
params: isA.object({
credentialId: base64urlCredentialId().required(),
}),
payload: isA.object({
name: isA.string().min(1).max(255).required(),
}),
},
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
e03adff to
afd9220
Compare
| }); | ||
|
|
||
| it('returns undefined for a name with non-BMP characters (e.g. emoji)', () => { | ||
| expect(validatePasskeyName('My Passkey \u{1F510}')).toBeUndefined(); |
There was a problem hiding this comment.
Yes, intentional. I'll re-word the test case so it's easier to read. The validation here matches the auth-server validator (DISPLAY_SAFE_UNICODE_WITH_NON_BMP) — the same rule used for device names.
| const jwt = this.getCachedJwtByScope('passkey'); | ||
| await this.withLoadingStatus( | ||
| this.authClient.renamePasskey(jwt, credentialId, name) | ||
| this.authClient.renamePasskey(sessionToken()!, credentialId, name) |
There was a problem hiding this comment.
Not something we need to address in this PR, but IMO using ! like this circumvents type safety.
There was a problem hiding this comment.
Thanks for calling this out. We have a lot of this pattern in the file, but that doesn't mean I need to follow it. Fixed.
| send_in_pings: | ||
| - events | ||
| notification_emails: | ||
| - vzare@mozilla.com |
There was a problem hiding this comment.
Not sure we need vesta on these anymore, tbh
There was a problem hiding this comment.
I was wondering about that - we may want to update globally for all metrics.
Because:
* Passkeys are auto-named generically at creation and users had no way to
rename them afterward.
This commit:
* Adds a rename control (passkey name + pencil) on the passkey SubRow that
opens a modal dialog with Save/Cancel.
* Switches PATCH /passkey/{credentialId} from the MFA JWT strategy to a
verified session token; rename is non-destructive, so no OTP step-up.
* Adds a sessionPatch auth-client helper and repoints renamePasskey to the
session token; Account.renamePasskey uses the cached session token.
* Validates on submit (non-empty, max 255, display-safe unicode, plus a
client-side duplicate-name guard) with an inline error message.
* Adds Glean rename view/submit/success/error events, FTL strings, and tests.
Closes #FXA-13962
Because
Passkey"), and users had no way to rename them to something meaningful.
way passkey removal does.
This pull request
packages/fxa-settings/src/components/Settings/SubRow/index.tsx:the passkey name and a decorative pencil form a single button that opens a rename
modal dialog (
PasskeyRenameModal, reusing the sameModalcomponent as the delete dialog)with Save/Cancel.
PATCH /passkey/{credentialId}inpackages/fxa-auth-server/lib/routes/passkeys.tsfrom the
mfastrategy toverifiedSessionToken; the delete route keeps its MFA guard.sessionPatchhelper inpackages/fxa-auth-client/lib/client.tsand repointsrenamePasskeyto a session token;Account.renamePasskeyuses the cached session token.client-side duplicate-name guard) and shows an inline error without calling the API until valid.
passkey_renameview/submit/success/error events (fxa-ui-metrics.yaml+ regeneratedweb bindings) and new FTL strings in
SubRow/en.ftl.Issue that this pull request solves
Closes: FXA-13962
Checklist
Put an
xin the boxes that applyHow to review (Optional)
packages/fxa-auth-server/lib/routes/passkeys.ts(rename → verified session token; delete unchanged) and the rename modal + validation in
packages/fxa-settings/src/components/Settings/SubRow/index.tsx.passkeys.ts→client.ts→Account.ts→SubRow/index.tsx→ tests.handler scopes the DB write by
uid+credentialId, so ownership is server-enforced.Screenshots (Optional)
Please attach the screenshots of the changes made in case of change in user interface.
Other information (Optional)
Any other information that is important to this pull request.