-
Notifications
You must be signed in to change notification settings - Fork 281
MNTOR-4586/recent authentication before deletion #6276
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,6 +9,7 @@ import { signOut } from "next-auth/react"; | |
| import { Button } from "../../../../../../components/client/Button"; | ||
| import { type onDeleteAccount } from "./actions"; | ||
| import { useTelemetry } from "../../../../../../hooks/useTelemetry"; | ||
| import { useL10n } from "../../../../../../hooks/l10n"; | ||
|
|
||
| /** | ||
| * Since <Button> is a client component, the `onDeleteAccount` handler can only | ||
|
|
@@ -21,29 +22,57 @@ export const DeleteAccountButton = ( | |
| onDeleteAccount: typeof onDeleteAccount; | ||
| }, | ||
| ) => { | ||
| const l10n = useL10n(); | ||
| const recordTelemetry = useTelemetry(); | ||
| const [isSubmitting, setIsSubmitting] = useState(false); | ||
| const [errorMessage, setErrorMessage] = useState<string | null>(null); | ||
| return ( | ||
| <Button | ||
| {...props} | ||
| isLoading={isSubmitting} | ||
| isDisabled={isSubmitting} | ||
| onPress={() => { | ||
| recordTelemetry("ctaButton", "click", { | ||
| button_id: "confirm_delete_account", | ||
| }); | ||
| setIsSubmitting(true); | ||
| // It's currently unclear if and how we should mock our server action: | ||
| /* c8 ignore next 8 */ | ||
| void props | ||
| .onDeleteAccount() | ||
| .then(() => { | ||
| void signOut({ callbackUrl: "/" }); | ||
| }) | ||
| .catch(() => { | ||
| setIsSubmitting(false); | ||
| <> | ||
| <Button | ||
| {...props} | ||
| isLoading={isSubmitting} | ||
| isDisabled={isSubmitting} | ||
| onPress={() => { | ||
| recordTelemetry("ctaButton", "click", { | ||
| button_id: "confirm_delete_account", | ||
| }); | ||
| }} | ||
| /> | ||
| setIsSubmitting(true); | ||
| setErrorMessage(null); | ||
| // It's currently unclear if and how we should mock our server action: | ||
| /* c8 ignore next 13 */ | ||
| void props | ||
| .onDeleteAccount() | ||
| .then((result) => { | ||
| if (result && typeof result === "object" && "success" in result) { | ||
| if (result.success === false) { | ||
| setIsSubmitting(false); | ||
| setErrorMessage( | ||
| result.errorMessage ?? | ||
| l10n.getString("settings-delete-account-error-generic"), | ||
| ); | ||
| return; | ||
| } | ||
| } | ||
| void signOut({ callbackUrl: "/" }); | ||
| }) | ||
| .catch(() => { | ||
| setIsSubmitting(false); | ||
| setErrorMessage( | ||
| l10n.getString("settings-delete-account-error-generic"), | ||
| ); | ||
| }); | ||
| }} | ||
| /> | ||
| {errorMessage && ( | ||
| <p | ||
| role="status" | ||
| style={{ | ||
| marginTop: "0.5rem", | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Probably doesn't matter for such a small and rarely visible surface, but we tend to avoid Again, probably not a biggie for this specific code, but good to know. |
||
| }} | ||
| > | ||
| {errorMessage} | ||
| </p> | ||
| )} | ||
| </> | ||
| ); | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -118,6 +118,9 @@ export const authOptions: AuthOptions = { | |
| }, | ||
| // Unused arguments also listed to show what's available: | ||
| async jwt({ token, account, profile, trigger }) { | ||
| if (account) { | ||
| token.authenticatedAt = Date.now(); | ||
| } | ||
| if (trigger === "update") { | ||
| // Refresh the user data from FxA, in case e.g. new subscriptions got added: | ||
| const subscriberFromDb = await getSubscriberByFxaUid( | ||
|
|
@@ -298,6 +301,9 @@ export const authOptions: AuthOptions = { | |
| } | ||
| } | ||
| } | ||
| if (token.authenticatedAt) { | ||
| session.authenticatedAt = new Date(token.authenticatedAt).toISOString(); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Isn't it safer to just keep the UNIX timestamp here? I don't think we need to preserve the timezone for this use case, so it would be good to be able to be able to avoid date string parsing. |
||
| } | ||
|
|
||
| return session; | ||
| }, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -46,6 +46,7 @@ declare module "next-auth" { | |
| /** Session data available after deserialising the JWT */ | ||
| interface Session { | ||
| error?: "RefreshAccessTokenError"; | ||
| authenticatedAt?: ISO8601DateString; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As above, wouldn't it make sense to use a UNIX timestamp here as well? |
||
| user: { | ||
| fxa?: { | ||
| /** The value of the Accept-Language header when the user signed up for their Firefox Account */ | ||
|
|
@@ -76,5 +77,6 @@ declare module "next-auth/jwt" { | |
| subscriptions: Array<string>; | ||
| }; | ||
| subscriber?: SerializedSubscriber; | ||
| authenticatedAt?: number; | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wordsmithing isn't my expertise, but "within the last hour" is confusing to me for something the user still has to do.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it mean "log in again within the next hour", or you "must have done the log in within the last hour"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think that the timing is particularly helpful to the user here. Why not just say, "For your safety, please sign in again before deleting your account." ?