Repository navigation
feat(admin): revoke sessions and notify when an admin changes a user's email or phone - #485
Merged
Merged
Conversation
…s email or phone Closes #475.
This was referenced Oct 22, 2026
…hange-notice # Conflicts: # src/controllers/admin.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #475.
What
When
PATCH /admin/users/{userId}changes a user'semailorphone:revokedReason: admin_identity_change) in the same transaction as the user update, so a failed revocation cannot leave the new address stored and the change undetectable on a retry. Access tokens already issued stay valid until they expire, the same as the existing admin revoke-all route.internal_user_updated_by_ownerevent gainsidentityChanges(field,previousSha256,nextSha256),revokedSessionsandnotices(per recipient:sent,failedornot_sent_external_delivery). Audit metadata is redacted of addresses before storage, so the values are kept as SHA-256 digests of the normalized form rather than in the clear; an investigator can still confirm whether a given address was the one removed or added. No new event type, so the event type enum is unchanged.An email that differs only in case is not treated as a change. Changing only
emailVerified,phoneVerifiedor roles does not revoke sessions.Messaging contract
@seamless-auth/messaging0.2.0 has templates only for OTP, magic link and enrollment invite, so there is no suitable template for an account notice. Rather than add a contract field, the notice goes through the closest generic path: the configuredEmailTransport.send/SmsTransport.send(the transport contract's genericEmailMessage/SmsMessage), with the text written in the API.directMessaging.tsnow exposescreateDirectEmailTransport/createDirectSmsTransportfor that, andmessagingService.tsaddssendNoticeEmail/sendNoticeSms, which follow the same development bypass andDeliveryErrorhandling as the other senders.External delivery:
AuthDeliverySchemain@seamless-auth/typeshas no kind for an account notice, so withx-seamless-auth-delivery-mode: externalthe API sends nothing itself (the caller owns delivery) and records each notice asnot_sent_external_delivery. A follow-up could add anaccount_noticedelivery kind to the types and messaging contracts so adopters who own delivery get these too.Step-up for this route is #437 and is not part of this change.
Contract
Response shape is unchanged (
UserResponseSchema). The onlyopenapi.json/src/generated/api.tschange is adescriptionon the route. Behaviour change worth noting for the admin dashboard: editing a user's email or phone now signs that user out.Checks
npm run typecheck: passnpm run lint: passnpx prettier --check .: passnpm run build: passnpm run coverage: pass, 142 files, 1995 tests passed (1 todo), thresholds met (all files 98.91% statements, 95.4% branches, 99.21% functions, 99.15% lines)