Skip to content

fix(passkeys): send new-device login email and notifications on passkey sign-in#20723

Open
vpomerleau wants to merge 1 commit into
mainfrom
FXA-13905
Open

fix(passkeys): send new-device login email and notifications on passkey sign-in#20723
vpomerleau wants to merge 1 commit into
mainfrom
FXA-13905

Conversation

@vpomerleau

@vpomerleau vpomerleau commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Because

  • Signing in with a passkey sent no "New sign-in to your Mozilla account" email — for synced or non-synced accounts — even though password sign-in does, leaving users without the new-sign-in security notification.
  • We set out to fix that missing email, and while implementing it found several related notification/email misalignments on the passkey path worth correcting in the same change: it also skipped the attached-services notification, login metrics, and security event; its email lacked the relying-party name and flow metrics context; and a shared, pre-existing regression was mislabeling direct Settings sign-ins (password sign-in included).

This pull request

  • Sends the new-device-login email and notifyAttachedServices('login') on passkey authenticationFinish (both sync and non-sync), reusing the shared notifyAttachedServicesForAccountSession helper.
  • Emits the account.login metrics event, flow-complete signal, and security event for non-sync sign-ins; Sync skips these because /session/reauth already emits them downstream (avoids double-counting).
  • Names the relying party in the email for OAuth sign-ins (the client forwards the clientId) and uses the generic "New sign-in to your Mozilla account" for non-OAuth and Sync sign-ins.
  • Forwards the flow metricsContext through /passkey/authentication/finish so the sign-in and its email are attributed to the flow.
  • Fixes a shared, pre-existing regression (~Feb 2026, from the passwordless-OTP clientIdFallback): a non-OAuth Web integration's getClientId() falls back to the first-party Settings client, which was sent as the email service and mislabeled direct Settings sign-ins as "New sign-in to Firefox Accounts Settings". Now gated on isOAuthIntegration in both the passkey (packages/fxa-settings/src/lib/passkeys/signin-flow.ts) and password (packages/fxa-settings/src/pages/Signin/container.tsx) sign-in paths, so direct Settings sign-ins read "Mozilla account" for both.
  • Wires the legacy mailer + oauthClientInfoService into the passkey routes (packages/fxa-auth-server/lib/routes/passkeys.ts).

Issue that this pull request solves

Closes: FXA-13905

Checklist

Put an x in the boxes that apply

  • My commit is GPG signed.
  • If applicable, I have modified or added tests which pass locally.
  • I have added necessary documentation (if appropriate).
  • I have verified that my changes render correctly in RTL (if appropriate).
  • I have manually reviewed all AI generated code.

How to review (Optional)

  • Key files/areas to focus on: passkeys.ts (sendPostSigninNotifications — the sync vs non-sync split); the isOAuthIntegration clientId gate in signin-flow.ts and Signin/container.tsx.
  • Suggested review order: passkeys.tssignin-flow.tscontainer.tsx → tests.
  • Risky or complex parts: the sync vs non-sync split (avoids double-emitting account.login at /session/reauth); the shared clientId-forwarding gate intentionally touches the password path.

Screenshots (Optional)

N/A — no user-visible change (sign-in routing/notification logic only; no UI or FTL copy changed).

Other information (Optional)

  • Pre-merge review: /fxa-review run — APPROVE (0 critical/high).
  • The Web-integration subject fix is a shared, pre-existing regression that also corrects the password sign-in path — flagging in case the team wants it tracked under its own ticket.
  • Tests: auth-server passkeys.spec (66), settings signin-flow (40) + Signin container (50), plus functional email-subject assertions (non-OAuth + two-step Sync). All green; functional passkeyAuth + signin suites green.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aligns the passkey sign-in path with the password sign-in path by sending the missing post-sign-in security/notification signals (new-device-login email, attached-services login notification, metrics/security events) and by fixing a Settings Web-integration fallback that was incorrectly forwarding a first-party Settings clientId and mislabeling the email subject.

Changes:

  • Send new-device-login email + attached-services login notification on passkey authenticationFinish, and emit metrics/security events for non-Sync passkey sign-ins.
  • Forward flow metricsContext through passkey auth finish so emails/metrics are attributed to the originating flow.
  • Gate forwarding of clientId as email service behind isOAuthIntegration (in both passkey and password sign-in paths) to avoid mislabeling direct Settings sign-ins.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
packages/fxa-settings/src/pages/Signin/container.tsx Gate clientId forwarding behind isOAuthIntegration to avoid mislabeling Settings sign-ins.
packages/fxa-settings/src/pages/Signin/container.test.tsx Add regression test ensuring WebIntegration fallback clientId is not forwarded as email service.
packages/fxa-settings/src/lib/passkeys/signin-flow.ts Forward correct service (Firefox service vs OAuth clientId) and pass metricsContext into passkey finish.
packages/fxa-settings/src/lib/passkeys/signin-flow.test.tsx Update/add tests for service forwarding rules and metricsContext forwarding in passkey sign-in.
packages/fxa-auth-server/lib/types.ts Allow AuthClientInfoService.fetch to accept an optional service for generic “Mozilla” resolution.
packages/fxa-auth-server/lib/routes/passkeys.ts Add post-sign-in notification sending for passkey auth finish; wire legacy mailer + oauth client info service; accept metricsContext.
packages/fxa-auth-server/lib/routes/passkeys.spec.ts Add coverage for email subject behavior, legacy mailer fallback, attached-services notify, metrics + security events.
packages/fxa-auth-server/lib/routes/index.js Pass mailer into passkeyRoutes wiring.
packages/fxa-auth-client/lib/client.ts Extend passkey finish call to support forwarding metricsContext.
packages/functional-tests/tests/passkeyAuth/passkeyPasswordFallback.spec.ts Assert new-device-login email subject for Sync passkey sign-in w/ password fallback.
packages/functional-tests/tests/passkeyAuth/passkey-signin.spec.ts Assert new-device-login email subject for direct Settings (non-OAuth Web integration) passkey sign-in.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/fxa-auth-client/lib/client.ts
@vpomerleau vpomerleau force-pushed the FXA-13905 branch 2 times, most recently from d714e54 to 62a597a Compare June 10, 2026 20:06
…ey sign-in

Because:
 - Passkey sign-in sent no "New sign-in" email and skipped the
   attached-services notification, metrics, and security event that password
   sign-in emits; the email also lacked the relying-party name and flow
   metrics context.

This commit:
 - Sends the new-device-login email and notifyAttachedServices('login') on
   passkey authenticationFinish (both sync and non-sync), reusing the shared
   notifyAttachedServicesForAccountSession helper.
 - Emits the account.login metrics event, flow signal, and security event for
   non-sync sign-ins; the sync flow's /session/reauth already emits these.
 - Names the relying party in the email for OAuth sign-ins (client forwards the
   clientId), and uses the generic "New sign-in to your Mozilla account" for
   non-OAuth and Sync sign-ins.
 - Forwards the flow metricsContext through /passkey/authentication/finish so
   the sign-in and its email are attributed to the flow.
 - Only forwards the clientId for genuine OAuth integrations: a Web (non-OAuth)
   integration's getClientId() can fall back to the first-party Settings client,
   which must not name the email. Applied to both the password and passkey
   paths so direct Settings sign-ins read "Mozilla account".
 - Wires the legacy mailer + oauthClientInfoService into the passkey routes.
 - Adds unit coverage (auth-server + settings) and functional assertions.

Closes: FXA-13905
@vpomerleau vpomerleau marked this pull request as ready for review June 10, 2026 20:45
@vpomerleau vpomerleau requested a review from a team as a code owner June 10, 2026 20:45

@vbudhram vbudhram left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vpomerleau Does this need to support Strapi customization? The new device emails are customized, but this wouldn't load them. Perhaps better as a follow up issue

OLDSYNC_SCOPE
);

const newDeviceLogin = await target.emailClient.waitForEmail(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for updating functional test

);
});

it('forces the generic "Mozilla account" email for a sync sign-in (no Firefox/Sync framing before keys)', async () => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The user intent was to sign into Sync, technically they didnt complete it. Still seems useful (maybe more simple?) to not have this special case.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Product is requesting that we send a separate (additional) email when the Firefox sign-in is completed, that will go in a follow-up ticket - so this one notifies that access to the account was granted.

In testing these flows, I'd also noticed that emails were getting sent with "New sign-in to Firefox Account Settings", which we definitely don't want.

@vpomerleau

Copy link
Copy Markdown
Contributor Author

Good callout about the customization @vbudhram. We already have a generic fast-follow ticket for applying customization in the passkey pages and flows, so I added an additional requirement there about emails.

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.

3 participants