From 9488a4dfed0145cc5965d07bd140c0c89ee9718d Mon Sep 17 00:00:00 2001 From: Vaggelis Yfantis Date: Wed, 19 Nov 2025 13:11:46 +0200 Subject: [PATCH 01/29] feat(clerk-js): Initial work for reset password task --- .../tasks/TaskResetPassword/withTaskGuard.ts | 26 ++++++++++++++++ .../components/SignIn/AlternativeMethods.tsx | 8 ++++- .../ui/components/SignIn/SignInFactorOne.tsx | 30 +++++++++++++++---- .../SignIn/SignInFactorOnePasswordCard.tsx | 21 +++++++++---- .../src/ui/elements/contexts/index.tsx | 1 + packages/localizations/src/en-US.ts | 3 ++ packages/shared/src/error.ts | 1 + packages/shared/src/errors/helpers.ts | 9 ++++++ packages/shared/src/types/localization.ts | 3 ++ 9 files changed, 90 insertions(+), 12 deletions(-) create mode 100644 packages/clerk-js/src/ui/components/SessionTasks/tasks/TaskResetPassword/withTaskGuard.ts diff --git a/packages/clerk-js/src/ui/components/SessionTasks/tasks/TaskResetPassword/withTaskGuard.ts b/packages/clerk-js/src/ui/components/SessionTasks/tasks/TaskResetPassword/withTaskGuard.ts new file mode 100644 index 00000000000..8545c2b1ffc --- /dev/null +++ b/packages/clerk-js/src/ui/components/SessionTasks/tasks/TaskResetPassword/withTaskGuard.ts @@ -0,0 +1,26 @@ +import type { ComponentType } from 'react'; + +import { warnings } from '@/core/warnings'; +import { withRedirect } from '@/ui/common'; +import { useTaskResetPasswordContext } from '@/ui/contexts/components/SessionTasks'; +import type { AvailableComponentProps } from '@/ui/types'; + +export const withTaskGuard =

(Component: ComponentType

) => { + const displayName = Component.displayName || Component.name || 'Component'; + Component.displayName = displayName; + + const HOC = (props: P) => { + const ctx = useTaskResetPasswordContext(); + return withRedirect( + Component, + clerk => !clerk.session?.currentTask, + ({ clerk }) => + !clerk.session ? clerk.buildSignInUrl() : (ctx.redirectUrlComplete ?? clerk.buildAfterSignInUrl()), + warnings.cannotRenderComponentWhenTaskDoesNotExist, + )(props); + }; + + HOC.displayName = `withTaskGuard(${displayName})`; + + return HOC; +}; diff --git a/packages/clerk-js/src/ui/components/SignIn/AlternativeMethods.tsx b/packages/clerk-js/src/ui/components/SignIn/AlternativeMethods.tsx index 8ca576bdab1..55ff9808bc0 100644 --- a/packages/clerk-js/src/ui/components/SignIn/AlternativeMethods.tsx +++ b/packages/clerk-js/src/ui/components/SignIn/AlternativeMethods.tsx @@ -18,7 +18,7 @@ import { SignInSocialButtons } from './SignInSocialButtons'; import { useResetPasswordFactor } from './useResetPasswordFactor'; import { withHavingTrouble } from './withHavingTrouble'; -type AlternativeMethodsMode = 'forgot' | 'pwned' | 'default'; +export type AlternativeMethodsMode = 'forgot' | 'pwned' | 'default' | 'untrusted-password'; export type AlternativeMethodsProps = { onBackLinkClick: React.MouseEventHandler | undefined; @@ -183,6 +183,8 @@ function determineFlowPart(mode: AlternativeMethodsMode) { return 'forgotPasswordMethods'; case 'pwned': return 'passwordPwnedMethods'; + case 'untrusted-password': + return 'untrustedPasswordMethods'; default: return 'alternativeMethods'; } @@ -194,6 +196,8 @@ function determineTitle(mode: AlternativeMethodsMode): LocalizationKey { return localizationKeys('signIn.forgotPasswordAlternativeMethods.title'); case 'pwned': return localizationKeys('signIn.passwordPwned.title'); + case 'untrusted-password': + return localizationKeys('signIn.passwordUntrusted.title'); default: return localizationKeys('signIn.alternativeMethods.title'); } @@ -204,6 +208,8 @@ function determineIsReset(mode: AlternativeMethodsMode): boolean { case 'forgot': case 'pwned': return true; + case 'untrusted-password': + return false; default: return false; } diff --git a/packages/clerk-js/src/ui/components/SignIn/SignInFactorOne.tsx b/packages/clerk-js/src/ui/components/SignIn/SignInFactorOne.tsx index e318345e719..bf8e8c2e61e 100644 --- a/packages/clerk-js/src/ui/components/SignIn/SignInFactorOne.tsx +++ b/packages/clerk-js/src/ui/components/SignIn/SignInFactorOne.tsx @@ -11,6 +11,7 @@ import { useCoreSignIn, useEnvironment } from '../../contexts'; import { useAlternativeStrategies } from '../../hooks/useAlternativeStrategies'; import { localizationKeys } from '../../localization'; import { useRouter } from '../../router'; +import type { AlternativeMethodsMode } from './AlternativeMethods'; import { AlternativeMethods } from './AlternativeMethods'; import { hasMultipleEnterpriseConnections } from './shared'; import { SignInFactorOneAlternativePhoneCodeCard } from './SignInFactorOneAlternativePhoneCodeCard'; @@ -41,6 +42,25 @@ const factorKey = (factor: SignInFactor | null | undefined) => { return key; }; +function determineAlternativeMethodsMode( + showForgotPasswordStrategies: boolean, + compromisedPasswordErrorCode: string | null, +): AlternativeMethodsMode { + if (!showForgotPasswordStrategies) { + return 'default'; + } + + if (compromisedPasswordErrorCode === 'form_password_pwned__sign_in') { + return 'pwned'; + } + + if (compromisedPasswordErrorCode === 'form_password_untrusted__sign_in') { + return 'untrusted-password'; + } + + return 'forgot'; +} + function SignInFactorOneInternal(): JSX.Element { const { __internal_setActiveInProgress } = useClerk(); const signIn = useCoreSignIn(); @@ -84,7 +104,7 @@ function SignInFactorOneInternal(): JSX.Element { const [showForgotPasswordStrategies, setShowForgotPasswordStrategies] = React.useState(false); - const [isPasswordPwned, setIsPasswordPwned] = React.useState(false); + const [untrustedPasswordErrorCode, setUntrustedPasswordErrorCode] = React.useState(null); React.useEffect(() => { if (__internal_setActiveInProgress) { @@ -139,11 +159,11 @@ function SignInFactorOneInternal(): JSX.Element { const toggle = showAllStrategies ? toggleAllStrategies : toggleForgotPasswordStrategies; const backHandler = () => { card.setError(undefined); - setIsPasswordPwned(false); + setUntrustedPasswordErrorCode(null); toggle?.(); }; - const mode = showForgotPasswordStrategies ? (isPasswordPwned ? 'pwned' : 'forgot') : 'default'; + const mode = determineAlternativeMethodsMode(showForgotPasswordStrategies, untrustedPasswordErrorCode); return ( { - setIsPasswordPwned(true); + onUntrustedPassword={() => { + setUntrustedPasswordErrorCode('form_password_pwned__sign_in'); toggleForgotPasswordStrategies(); }} /> diff --git a/packages/clerk-js/src/ui/components/SignIn/SignInFactorOnePasswordCard.tsx b/packages/clerk-js/src/ui/components/SignIn/SignInFactorOnePasswordCard.tsx index f7e05371cee..93c0d910035 100644 --- a/packages/clerk-js/src/ui/components/SignIn/SignInFactorOnePasswordCard.tsx +++ b/packages/clerk-js/src/ui/components/SignIn/SignInFactorOnePasswordCard.tsx @@ -1,4 +1,4 @@ -import { isPasswordPwnedError, isUserLockedError } from '@clerk/shared/error'; +import { isPasswordPwnedError, isPasswordUntrustedError, isUserLockedError } from '@clerk/shared/error'; import { useClerk } from '@clerk/shared/react'; import React from 'react'; @@ -21,7 +21,7 @@ import { useResetPasswordFactor } from './useResetPasswordFactor'; type SignInFactorOnePasswordProps = { onForgotPasswordMethodClick: React.MouseEventHandler | undefined; onShowAlternativeMethodsClick: React.MouseEventHandler | undefined; - onPasswordPwned?: () => void; + onUntrustedPassword?: (errorCode: string) => void; }; const usePasswordControl = (props: SignInFactorOnePasswordProps) => { @@ -50,7 +50,7 @@ const usePasswordControl = (props: SignInFactorOnePasswordProps) => { }; export const SignInFactorOnePasswordCard = (props: SignInFactorOnePasswordProps) => { - const { onShowAlternativeMethodsClick, onPasswordPwned } = props; + const { onShowAlternativeMethodsClick, onUntrustedPassword } = props; const passwordInputRef = React.useRef(null); const card = useCardState(); const { setActive } = useClerk(); @@ -92,9 +92,18 @@ export const SignInFactorOnePasswordCard = (props: SignInFactorOnePasswordProps) return clerk.__internal_navigateWithError('..', err.errors[0]); } - if (isPasswordPwnedError(err) && onPasswordPwned) { - card.setError({ ...err.errors[0], code: 'form_password_pwned__sign_in' }); - onPasswordPwned(); + if (onUntrustedPassword) { + // TODO(vaggelis): those will eventually be unified into a single error code + if (isPasswordPwnedError(err)) { + card.setError({ ...err.errors[0], code: 'form_password_pwned__sign_in' }); + onUntrustedPassword('form_password_pwned__sign_in'); + return; + } + if (isPasswordUntrustedError(err)) { + card.setError({ ...err.errors[0], code: 'form_password_untrusted__sign_in' }); + onUntrustedPassword('form_password_untrusted__sign_in'); + return; + } return; } diff --git a/packages/clerk-js/src/ui/elements/contexts/index.tsx b/packages/clerk-js/src/ui/elements/contexts/index.tsx index 6211f1a0b84..5c4bb99a9e2 100644 --- a/packages/clerk-js/src/ui/elements/contexts/index.tsx +++ b/packages/clerk-js/src/ui/elements/contexts/index.tsx @@ -120,6 +120,7 @@ export type FlowMetadata = { | 'alternativeMethods' | 'forgotPasswordMethods' | 'passwordPwnedMethods' + | 'untrustedPasswordMethods' | 'havingTrouble' | 'ssoCallback' | 'popupCallback' diff --git a/packages/localizations/src/en-US.ts b/packages/localizations/src/en-US.ts index 99d4822c1ce..54ea56b1dab 100644 --- a/packages/localizations/src/en-US.ts +++ b/packages/localizations/src/en-US.ts @@ -694,6 +694,9 @@ export const enUS: LocalizationResource = { passwordPwned: { title: 'Password compromised', }, + passwordUntrusted: { + title: 'Password untrusted', + }, phoneCode: { formTitle: 'Verification code', resendButton: "Didn't receive a code? Resend", diff --git a/packages/shared/src/error.ts b/packages/shared/src/error.ts index 14b32870d1f..2e9b9293866 100644 --- a/packages/shared/src/error.ts +++ b/packages/shared/src/error.ts @@ -24,6 +24,7 @@ export { isMetamaskError, isNetworkError, isPasswordPwnedError, + isPasswordUntrustedError, isReverificationCancelledError, isUnauthorizedError, isUserLockedError, diff --git a/packages/shared/src/errors/helpers.ts b/packages/shared/src/errors/helpers.ts index 046270fedf9..d7ba9963c71 100644 --- a/packages/shared/src/errors/helpers.ts +++ b/packages/shared/src/errors/helpers.ts @@ -120,6 +120,15 @@ export function isPasswordPwnedError(err: any) { return isClerkAPIResponseError(err) && err.errors?.[0]?.code === 'form_password_pwned'; } +/** + * Checks if the provided error is a clerk api response error indicating a password is untrusted. + * + * @internal + */ +export function isPasswordUntrustedError(err: any) { + return isClerkAPIResponseError(err) && err.errors?.[0]?.code === 'form_password_untrusted'; +} + /** * Checks if the provided error is an EmailLinkError. * diff --git a/packages/shared/src/types/localization.ts b/packages/shared/src/types/localization.ts index d46434cc2fe..8c9266d1469 100644 --- a/packages/shared/src/types/localization.ts +++ b/packages/shared/src/types/localization.ts @@ -400,6 +400,9 @@ export type __internal_LocalizationResource = { passwordPwned: { title: LocalizationValue; }; + passwordUntrusted: { + title: LocalizationValue; + }; passkey: { title: LocalizationValue; subtitle: LocalizationValue; From b6e2595b28c05cd9f50a5d7a70199712ae9a47d3 Mon Sep 17 00:00:00 2001 From: Vaggelis Yfantis Date: Wed, 19 Nov 2025 14:52:57 +0200 Subject: [PATCH 02/29] fix(clerk-js): Rename variable for clarity in SignInFactorOne component --- .../clerk-js/src/ui/components/SignIn/SignInFactorOne.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/clerk-js/src/ui/components/SignIn/SignInFactorOne.tsx b/packages/clerk-js/src/ui/components/SignIn/SignInFactorOne.tsx index bf8e8c2e61e..32265303933 100644 --- a/packages/clerk-js/src/ui/components/SignIn/SignInFactorOne.tsx +++ b/packages/clerk-js/src/ui/components/SignIn/SignInFactorOne.tsx @@ -44,17 +44,17 @@ const factorKey = (factor: SignInFactor | null | undefined) => { function determineAlternativeMethodsMode( showForgotPasswordStrategies: boolean, - compromisedPasswordErrorCode: string | null, + untrustedPasswordErrorCode: string | null, ): AlternativeMethodsMode { if (!showForgotPasswordStrategies) { return 'default'; } - if (compromisedPasswordErrorCode === 'form_password_pwned__sign_in') { + if (untrustedPasswordErrorCode === 'form_password_pwned__sign_in') { return 'pwned'; } - if (compromisedPasswordErrorCode === 'form_password_untrusted__sign_in') { + if (untrustedPasswordErrorCode === 'form_password_untrusted__sign_in') { return 'untrusted-password'; } From 10795dd13cc2a26603269dd06dc441ce4c4104da Mon Sep 17 00:00:00 2001 From: Vaggelis Yfantis Date: Thu, 20 Nov 2025 15:44:04 +0200 Subject: [PATCH 03/29] revert(clerk-js): Remove the logic for sign-in error on untrusted password --- .../components/SignIn/AlternativeMethods.tsx | 8 +---- .../ui/components/SignIn/SignInFactorOne.tsx | 30 ++++--------------- .../SignIn/SignInFactorOnePasswordCard.tsx | 21 ++++--------- packages/shared/src/error.ts | 1 - packages/shared/src/errors/helpers.ts | 9 ------ 5 files changed, 12 insertions(+), 57 deletions(-) diff --git a/packages/clerk-js/src/ui/components/SignIn/AlternativeMethods.tsx b/packages/clerk-js/src/ui/components/SignIn/AlternativeMethods.tsx index 55ff9808bc0..8ca576bdab1 100644 --- a/packages/clerk-js/src/ui/components/SignIn/AlternativeMethods.tsx +++ b/packages/clerk-js/src/ui/components/SignIn/AlternativeMethods.tsx @@ -18,7 +18,7 @@ import { SignInSocialButtons } from './SignInSocialButtons'; import { useResetPasswordFactor } from './useResetPasswordFactor'; import { withHavingTrouble } from './withHavingTrouble'; -export type AlternativeMethodsMode = 'forgot' | 'pwned' | 'default' | 'untrusted-password'; +type AlternativeMethodsMode = 'forgot' | 'pwned' | 'default'; export type AlternativeMethodsProps = { onBackLinkClick: React.MouseEventHandler | undefined; @@ -183,8 +183,6 @@ function determineFlowPart(mode: AlternativeMethodsMode) { return 'forgotPasswordMethods'; case 'pwned': return 'passwordPwnedMethods'; - case 'untrusted-password': - return 'untrustedPasswordMethods'; default: return 'alternativeMethods'; } @@ -196,8 +194,6 @@ function determineTitle(mode: AlternativeMethodsMode): LocalizationKey { return localizationKeys('signIn.forgotPasswordAlternativeMethods.title'); case 'pwned': return localizationKeys('signIn.passwordPwned.title'); - case 'untrusted-password': - return localizationKeys('signIn.passwordUntrusted.title'); default: return localizationKeys('signIn.alternativeMethods.title'); } @@ -208,8 +204,6 @@ function determineIsReset(mode: AlternativeMethodsMode): boolean { case 'forgot': case 'pwned': return true; - case 'untrusted-password': - return false; default: return false; } diff --git a/packages/clerk-js/src/ui/components/SignIn/SignInFactorOne.tsx b/packages/clerk-js/src/ui/components/SignIn/SignInFactorOne.tsx index 32265303933..e318345e719 100644 --- a/packages/clerk-js/src/ui/components/SignIn/SignInFactorOne.tsx +++ b/packages/clerk-js/src/ui/components/SignIn/SignInFactorOne.tsx @@ -11,7 +11,6 @@ import { useCoreSignIn, useEnvironment } from '../../contexts'; import { useAlternativeStrategies } from '../../hooks/useAlternativeStrategies'; import { localizationKeys } from '../../localization'; import { useRouter } from '../../router'; -import type { AlternativeMethodsMode } from './AlternativeMethods'; import { AlternativeMethods } from './AlternativeMethods'; import { hasMultipleEnterpriseConnections } from './shared'; import { SignInFactorOneAlternativePhoneCodeCard } from './SignInFactorOneAlternativePhoneCodeCard'; @@ -42,25 +41,6 @@ const factorKey = (factor: SignInFactor | null | undefined) => { return key; }; -function determineAlternativeMethodsMode( - showForgotPasswordStrategies: boolean, - untrustedPasswordErrorCode: string | null, -): AlternativeMethodsMode { - if (!showForgotPasswordStrategies) { - return 'default'; - } - - if (untrustedPasswordErrorCode === 'form_password_pwned__sign_in') { - return 'pwned'; - } - - if (untrustedPasswordErrorCode === 'form_password_untrusted__sign_in') { - return 'untrusted-password'; - } - - return 'forgot'; -} - function SignInFactorOneInternal(): JSX.Element { const { __internal_setActiveInProgress } = useClerk(); const signIn = useCoreSignIn(); @@ -104,7 +84,7 @@ function SignInFactorOneInternal(): JSX.Element { const [showForgotPasswordStrategies, setShowForgotPasswordStrategies] = React.useState(false); - const [untrustedPasswordErrorCode, setUntrustedPasswordErrorCode] = React.useState(null); + const [isPasswordPwned, setIsPasswordPwned] = React.useState(false); React.useEffect(() => { if (__internal_setActiveInProgress) { @@ -159,11 +139,11 @@ function SignInFactorOneInternal(): JSX.Element { const toggle = showAllStrategies ? toggleAllStrategies : toggleForgotPasswordStrategies; const backHandler = () => { card.setError(undefined); - setUntrustedPasswordErrorCode(null); + setIsPasswordPwned(false); toggle?.(); }; - const mode = determineAlternativeMethodsMode(showForgotPasswordStrategies, untrustedPasswordErrorCode); + const mode = showForgotPasswordStrategies ? (isPasswordPwned ? 'pwned' : 'forgot') : 'default'; return ( { - setUntrustedPasswordErrorCode('form_password_pwned__sign_in'); + onPasswordPwned={() => { + setIsPasswordPwned(true); toggleForgotPasswordStrategies(); }} /> diff --git a/packages/clerk-js/src/ui/components/SignIn/SignInFactorOnePasswordCard.tsx b/packages/clerk-js/src/ui/components/SignIn/SignInFactorOnePasswordCard.tsx index 93c0d910035..f7e05371cee 100644 --- a/packages/clerk-js/src/ui/components/SignIn/SignInFactorOnePasswordCard.tsx +++ b/packages/clerk-js/src/ui/components/SignIn/SignInFactorOnePasswordCard.tsx @@ -1,4 +1,4 @@ -import { isPasswordPwnedError, isPasswordUntrustedError, isUserLockedError } from '@clerk/shared/error'; +import { isPasswordPwnedError, isUserLockedError } from '@clerk/shared/error'; import { useClerk } from '@clerk/shared/react'; import React from 'react'; @@ -21,7 +21,7 @@ import { useResetPasswordFactor } from './useResetPasswordFactor'; type SignInFactorOnePasswordProps = { onForgotPasswordMethodClick: React.MouseEventHandler | undefined; onShowAlternativeMethodsClick: React.MouseEventHandler | undefined; - onUntrustedPassword?: (errorCode: string) => void; + onPasswordPwned?: () => void; }; const usePasswordControl = (props: SignInFactorOnePasswordProps) => { @@ -50,7 +50,7 @@ const usePasswordControl = (props: SignInFactorOnePasswordProps) => { }; export const SignInFactorOnePasswordCard = (props: SignInFactorOnePasswordProps) => { - const { onShowAlternativeMethodsClick, onUntrustedPassword } = props; + const { onShowAlternativeMethodsClick, onPasswordPwned } = props; const passwordInputRef = React.useRef(null); const card = useCardState(); const { setActive } = useClerk(); @@ -92,18 +92,9 @@ export const SignInFactorOnePasswordCard = (props: SignInFactorOnePasswordProps) return clerk.__internal_navigateWithError('..', err.errors[0]); } - if (onUntrustedPassword) { - // TODO(vaggelis): those will eventually be unified into a single error code - if (isPasswordPwnedError(err)) { - card.setError({ ...err.errors[0], code: 'form_password_pwned__sign_in' }); - onUntrustedPassword('form_password_pwned__sign_in'); - return; - } - if (isPasswordUntrustedError(err)) { - card.setError({ ...err.errors[0], code: 'form_password_untrusted__sign_in' }); - onUntrustedPassword('form_password_untrusted__sign_in'); - return; - } + if (isPasswordPwnedError(err) && onPasswordPwned) { + card.setError({ ...err.errors[0], code: 'form_password_pwned__sign_in' }); + onPasswordPwned(); return; } diff --git a/packages/shared/src/error.ts b/packages/shared/src/error.ts index 2e9b9293866..14b32870d1f 100644 --- a/packages/shared/src/error.ts +++ b/packages/shared/src/error.ts @@ -24,7 +24,6 @@ export { isMetamaskError, isNetworkError, isPasswordPwnedError, - isPasswordUntrustedError, isReverificationCancelledError, isUnauthorizedError, isUserLockedError, diff --git a/packages/shared/src/errors/helpers.ts b/packages/shared/src/errors/helpers.ts index d7ba9963c71..046270fedf9 100644 --- a/packages/shared/src/errors/helpers.ts +++ b/packages/shared/src/errors/helpers.ts @@ -120,15 +120,6 @@ export function isPasswordPwnedError(err: any) { return isClerkAPIResponseError(err) && err.errors?.[0]?.code === 'form_password_pwned'; } -/** - * Checks if the provided error is a clerk api response error indicating a password is untrusted. - * - * @internal - */ -export function isPasswordUntrustedError(err: any) { - return isClerkAPIResponseError(err) && err.errors?.[0]?.code === 'form_password_untrusted'; -} - /** * Checks if the provided error is an EmailLinkError. * From dab6d2d1dbb2c7a34eb57f7fca8850de4aed4d1b Mon Sep 17 00:00:00 2001 From: Vaggelis Yfantis Date: Thu, 20 Nov 2025 15:44:57 +0200 Subject: [PATCH 04/29] refactor(clerk-js): Remove 'untrustedPasswordMethods' from FlowMetadata type --- packages/clerk-js/src/ui/elements/contexts/index.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/clerk-js/src/ui/elements/contexts/index.tsx b/packages/clerk-js/src/ui/elements/contexts/index.tsx index 5c4bb99a9e2..6211f1a0b84 100644 --- a/packages/clerk-js/src/ui/elements/contexts/index.tsx +++ b/packages/clerk-js/src/ui/elements/contexts/index.tsx @@ -120,7 +120,6 @@ export type FlowMetadata = { | 'alternativeMethods' | 'forgotPasswordMethods' | 'passwordPwnedMethods' - | 'untrustedPasswordMethods' | 'havingTrouble' | 'ssoCallback' | 'popupCallback' From c7f59ab4d4f990c0d71a5acb8b13c71856451531 Mon Sep 17 00:00:00 2001 From: Vaggelis Yfantis Date: Thu, 20 Nov 2025 19:53:20 +0200 Subject: [PATCH 05/29] refactor(localization): Remove 'passwordUntrusted' key from en-US localization files --- packages/localizations/src/en-US.ts | 3 --- packages/shared/src/types/localization.ts | 3 --- 2 files changed, 6 deletions(-) diff --git a/packages/localizations/src/en-US.ts b/packages/localizations/src/en-US.ts index 54ea56b1dab..99d4822c1ce 100644 --- a/packages/localizations/src/en-US.ts +++ b/packages/localizations/src/en-US.ts @@ -694,9 +694,6 @@ export const enUS: LocalizationResource = { passwordPwned: { title: 'Password compromised', }, - passwordUntrusted: { - title: 'Password untrusted', - }, phoneCode: { formTitle: 'Verification code', resendButton: "Didn't receive a code? Resend", diff --git a/packages/shared/src/types/localization.ts b/packages/shared/src/types/localization.ts index 8c9266d1469..d46434cc2fe 100644 --- a/packages/shared/src/types/localization.ts +++ b/packages/shared/src/types/localization.ts @@ -400,9 +400,6 @@ export type __internal_LocalizationResource = { passwordPwned: { title: LocalizationValue; }; - passwordUntrusted: { - title: LocalizationValue; - }; passkey: { title: LocalizationValue; subtitle: LocalizationValue; From 44b5c92dee5e779d4f4f9771b906d2e332811ebf Mon Sep 17 00:00:00 2001 From: Vaggelis Yfantis Date: Wed, 26 Nov 2025 13:39:09 +0200 Subject: [PATCH 06/29] fix(clerk-js): Update buildTasksUrl method to accept optional redirectUrl parameter --- packages/shared/src/types/clerk.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/shared/src/types/clerk.ts b/packages/shared/src/types/clerk.ts index 84e3b5832b6..bf7e10288b3 100644 --- a/packages/shared/src/types/clerk.ts +++ b/packages/shared/src/types/clerk.ts @@ -744,7 +744,7 @@ export interface Clerk { /** * Returns the configured url where tasks are mounted. */ - buildTasksUrl(): string; + buildTasksUrl({ redirectUrl }?: { redirectUrl?: string }): string; /** * Returns the configured afterSignInUrl of the instance. From 4231a0c5ce116ce6f032e7267a28ea344c19ec68 Mon Sep 17 00:00:00 2001 From: Vaggelis Yfantis Date: Wed, 26 Nov 2025 13:49:01 +0200 Subject: [PATCH 07/29] fix(clerk-js): Update buildTasksUrl method to accept optional TasksRedirectOptions parameter --- packages/react/src/isomorphicClerk.ts | 4 ++-- packages/shared/src/types/clerk.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/react/src/isomorphicClerk.ts b/packages/react/src/isomorphicClerk.ts index fc8b450987f..f50686702fe 100644 --- a/packages/react/src/isomorphicClerk.ts +++ b/packages/react/src/isomorphicClerk.ts @@ -404,8 +404,8 @@ export class IsomorphicClerk implements IsomorphicLoadedClerk { } }; - buildTasksUrl = (): string | void => { - const callback = () => this.clerkjs?.buildTasksUrl() || ''; + buildTasksUrl = (opts?: TasksRedirectOptions): string | void => { + const callback = () => this.clerkjs?.buildTasksUrl(opts) || ''; if (this.clerkjs && this.loaded) { return callback(); } else { diff --git a/packages/shared/src/types/clerk.ts b/packages/shared/src/types/clerk.ts index bf7e10288b3..6f49b6289ea 100644 --- a/packages/shared/src/types/clerk.ts +++ b/packages/shared/src/types/clerk.ts @@ -744,7 +744,7 @@ export interface Clerk { /** * Returns the configured url where tasks are mounted. */ - buildTasksUrl({ redirectUrl }?: { redirectUrl?: string }): string; + buildTasksUrl(opts?: TasksRedirectOptions): string; /** * Returns the configured afterSignInUrl of the instance. From 89b95956cf698df12d457eae9cf5498766b93535 Mon Sep 17 00:00:00 2001 From: Vaggelis Yfantis Date: Wed, 26 Nov 2025 19:05:53 +0200 Subject: [PATCH 08/29] feat(clerk-js,backend): Implement reset password session task and related test cases --- .../SessionTasks/tasks/TaskResetPassword/withTaskGuard.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/clerk-js/src/ui/components/SessionTasks/tasks/TaskResetPassword/withTaskGuard.ts b/packages/clerk-js/src/ui/components/SessionTasks/tasks/TaskResetPassword/withTaskGuard.ts index 8545c2b1ffc..b145ef6c292 100644 --- a/packages/clerk-js/src/ui/components/SessionTasks/tasks/TaskResetPassword/withTaskGuard.ts +++ b/packages/clerk-js/src/ui/components/SessionTasks/tasks/TaskResetPassword/withTaskGuard.ts @@ -13,7 +13,7 @@ export const withTaskGuard =

(Component: Comp const ctx = useTaskResetPasswordContext(); return withRedirect( Component, - clerk => !clerk.session?.currentTask, + clerk => !clerk.session?.currentTask || clerk.session.currentTask.key !== 'reset-password', ({ clerk }) => !clerk.session ? clerk.buildSignInUrl() : (ctx.redirectUrlComplete ?? clerk.buildAfterSignInUrl()), warnings.cannotRenderComponentWhenTaskDoesNotExist, From 1309dcf6f1cde22f033c39c5ec38cf5127f6ac5c Mon Sep 17 00:00:00 2001 From: Vaggelis Yfantis Date: Wed, 26 Nov 2025 20:04:24 +0200 Subject: [PATCH 09/29] fix(clerk-js): Revert navigation changes from TaskChooseOrganization --- .changeset/yummy-geese-work.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/yummy-geese-work.md diff --git a/.changeset/yummy-geese-work.md b/.changeset/yummy-geese-work.md new file mode 100644 index 00000000000..7388c6df720 --- /dev/null +++ b/.changeset/yummy-geese-work.md @@ -0,0 +1,5 @@ +--- +'@clerk/clerk-react': minor +--- + +Expose `buildTasksUrl` parameters From bc25e24add3166c029f5a7fe3a6f32d112a843aa Mon Sep 17 00:00:00 2001 From: Vaggelis Yfantis Date: Wed, 26 Nov 2025 23:27:36 +0200 Subject: [PATCH 10/29] feat(clerk-js): Introduce 'passwordUntrusted' flow --- .../components/SignIn/AlternativeMethods.tsx | 12 ++++++-- .../ui/components/SignIn/SignInFactorOne.tsx | 30 +++++++++++++++---- .../SignIn/SignInFactorOnePasswordCard.tsx | 21 +++++++++---- .../src/ui/elements/contexts/index.tsx | 1 + packages/localizations/src/en-GB.ts | 3 ++ packages/shared/src/error.ts | 1 + packages/shared/src/errors/helpers.ts | 9 ++++++ packages/shared/src/types/localization.ts | 3 ++ 8 files changed, 67 insertions(+), 13 deletions(-) diff --git a/packages/clerk-js/src/ui/components/SignIn/AlternativeMethods.tsx b/packages/clerk-js/src/ui/components/SignIn/AlternativeMethods.tsx index 8ca576bdab1..95e41ac3f5d 100644 --- a/packages/clerk-js/src/ui/components/SignIn/AlternativeMethods.tsx +++ b/packages/clerk-js/src/ui/components/SignIn/AlternativeMethods.tsx @@ -18,7 +18,7 @@ import { SignInSocialButtons } from './SignInSocialButtons'; import { useResetPasswordFactor } from './useResetPasswordFactor'; import { withHavingTrouble } from './withHavingTrouble'; -type AlternativeMethodsMode = 'forgot' | 'pwned' | 'default'; +export type AlternativeMethodsMode = 'forgot' | 'pwned' | 'passwordUntrusted' | 'default'; export type AlternativeMethodsProps = { onBackLinkClick: React.MouseEventHandler | undefined; @@ -55,7 +55,9 @@ const AlternativeMethodsList = (props: AlternativeMethodListProps) => { - {!isReset && } + {!isReset && mode !== 'passwordUntrusted' && ( + + )} {card.error} {/*TODO: extract main in its own component */} @@ -183,6 +185,8 @@ function determineFlowPart(mode: AlternativeMethodsMode) { return 'forgotPasswordMethods'; case 'pwned': return 'passwordPwnedMethods'; + case 'passwordUntrusted': + return 'passwordUntrustedMethods'; default: return 'alternativeMethods'; } @@ -194,6 +198,8 @@ function determineTitle(mode: AlternativeMethodsMode): LocalizationKey { return localizationKeys('signIn.forgotPasswordAlternativeMethods.title'); case 'pwned': return localizationKeys('signIn.passwordPwned.title'); + case 'passwordUntrusted': + return localizationKeys('signIn.passwordPwned.title'); default: return localizationKeys('signIn.alternativeMethods.title'); } @@ -204,6 +210,8 @@ function determineIsReset(mode: AlternativeMethodsMode): boolean { case 'forgot': case 'pwned': return true; + case 'passwordUntrusted': + return false; default: return false; } diff --git a/packages/clerk-js/src/ui/components/SignIn/SignInFactorOne.tsx b/packages/clerk-js/src/ui/components/SignIn/SignInFactorOne.tsx index e318345e719..16e962ffb19 100644 --- a/packages/clerk-js/src/ui/components/SignIn/SignInFactorOne.tsx +++ b/packages/clerk-js/src/ui/components/SignIn/SignInFactorOne.tsx @@ -11,6 +11,7 @@ import { useCoreSignIn, useEnvironment } from '../../contexts'; import { useAlternativeStrategies } from '../../hooks/useAlternativeStrategies'; import { localizationKeys } from '../../localization'; import { useRouter } from '../../router'; +import type { AlternativeMethodsMode } from './AlternativeMethods'; import { AlternativeMethods } from './AlternativeMethods'; import { hasMultipleEnterpriseConnections } from './shared'; import { SignInFactorOneAlternativePhoneCodeCard } from './SignInFactorOneAlternativePhoneCodeCard'; @@ -41,6 +42,25 @@ const factorKey = (factor: SignInFactor | null | undefined) => { return key; }; +function determineAlternativeMethodsMode( + showForgotPasswordStrategies: boolean, + untrustedPasswordErrorCode: string | null, +): AlternativeMethodsMode { + if (!showForgotPasswordStrategies) { + return 'default'; + } + + if (untrustedPasswordErrorCode === 'form_password_pwned__sign_in') { + return 'pwned'; + } + + if (untrustedPasswordErrorCode === 'form_password_untrusted__sign_in') { + return 'passwordUntrusted'; + } + + return 'forgot'; +} + function SignInFactorOneInternal(): JSX.Element { const { __internal_setActiveInProgress } = useClerk(); const signIn = useCoreSignIn(); @@ -84,7 +104,7 @@ function SignInFactorOneInternal(): JSX.Element { const [showForgotPasswordStrategies, setShowForgotPasswordStrategies] = React.useState(false); - const [isPasswordPwned, setIsPasswordPwned] = React.useState(false); + const [untrustedPasswordErrorCode, setUntrustedPasswordErrorCode] = React.useState(null); React.useEffect(() => { if (__internal_setActiveInProgress) { @@ -139,11 +159,11 @@ function SignInFactorOneInternal(): JSX.Element { const toggle = showAllStrategies ? toggleAllStrategies : toggleForgotPasswordStrategies; const backHandler = () => { card.setError(undefined); - setIsPasswordPwned(false); + setUntrustedPasswordErrorCode(null); toggle?.(); }; - const mode = showForgotPasswordStrategies ? (isPasswordPwned ? 'pwned' : 'forgot') : 'default'; + const mode = determineAlternativeMethodsMode(showForgotPasswordStrategies, untrustedPasswordErrorCode); return ( { - setIsPasswordPwned(true); + onUntrustedPassword={errorCode => { + setUntrustedPasswordErrorCode(errorCode); toggleForgotPasswordStrategies(); }} /> diff --git a/packages/clerk-js/src/ui/components/SignIn/SignInFactorOnePasswordCard.tsx b/packages/clerk-js/src/ui/components/SignIn/SignInFactorOnePasswordCard.tsx index f7e05371cee..93c0d910035 100644 --- a/packages/clerk-js/src/ui/components/SignIn/SignInFactorOnePasswordCard.tsx +++ b/packages/clerk-js/src/ui/components/SignIn/SignInFactorOnePasswordCard.tsx @@ -1,4 +1,4 @@ -import { isPasswordPwnedError, isUserLockedError } from '@clerk/shared/error'; +import { isPasswordPwnedError, isPasswordUntrustedError, isUserLockedError } from '@clerk/shared/error'; import { useClerk } from '@clerk/shared/react'; import React from 'react'; @@ -21,7 +21,7 @@ import { useResetPasswordFactor } from './useResetPasswordFactor'; type SignInFactorOnePasswordProps = { onForgotPasswordMethodClick: React.MouseEventHandler | undefined; onShowAlternativeMethodsClick: React.MouseEventHandler | undefined; - onPasswordPwned?: () => void; + onUntrustedPassword?: (errorCode: string) => void; }; const usePasswordControl = (props: SignInFactorOnePasswordProps) => { @@ -50,7 +50,7 @@ const usePasswordControl = (props: SignInFactorOnePasswordProps) => { }; export const SignInFactorOnePasswordCard = (props: SignInFactorOnePasswordProps) => { - const { onShowAlternativeMethodsClick, onPasswordPwned } = props; + const { onShowAlternativeMethodsClick, onUntrustedPassword } = props; const passwordInputRef = React.useRef(null); const card = useCardState(); const { setActive } = useClerk(); @@ -92,9 +92,18 @@ export const SignInFactorOnePasswordCard = (props: SignInFactorOnePasswordProps) return clerk.__internal_navigateWithError('..', err.errors[0]); } - if (isPasswordPwnedError(err) && onPasswordPwned) { - card.setError({ ...err.errors[0], code: 'form_password_pwned__sign_in' }); - onPasswordPwned(); + if (onUntrustedPassword) { + // TODO(vaggelis): those will eventually be unified into a single error code + if (isPasswordPwnedError(err)) { + card.setError({ ...err.errors[0], code: 'form_password_pwned__sign_in' }); + onUntrustedPassword('form_password_pwned__sign_in'); + return; + } + if (isPasswordUntrustedError(err)) { + card.setError({ ...err.errors[0], code: 'form_password_untrusted__sign_in' }); + onUntrustedPassword('form_password_untrusted__sign_in'); + return; + } return; } diff --git a/packages/clerk-js/src/ui/elements/contexts/index.tsx b/packages/clerk-js/src/ui/elements/contexts/index.tsx index 6211f1a0b84..1ad79f85d0c 100644 --- a/packages/clerk-js/src/ui/elements/contexts/index.tsx +++ b/packages/clerk-js/src/ui/elements/contexts/index.tsx @@ -120,6 +120,7 @@ export type FlowMetadata = { | 'alternativeMethods' | 'forgotPasswordMethods' | 'passwordPwnedMethods' + | 'passwordUntrustedMethods' | 'havingTrouble' | 'ssoCallback' | 'popupCallback' diff --git a/packages/localizations/src/en-GB.ts b/packages/localizations/src/en-GB.ts index 1192dfecc62..1854dbb1afc 100644 --- a/packages/localizations/src/en-GB.ts +++ b/packages/localizations/src/en-GB.ts @@ -697,6 +697,9 @@ export const enGB: LocalizationResource = { passwordPwned: { title: 'Password compromised', }, + passwordUntrusted: { + title: 'Password compromised', + }, phoneCode: { formTitle: 'Verification code', resendButton: "Didn't receive a code? Resend", diff --git a/packages/shared/src/error.ts b/packages/shared/src/error.ts index 14b32870d1f..2e9b9293866 100644 --- a/packages/shared/src/error.ts +++ b/packages/shared/src/error.ts @@ -24,6 +24,7 @@ export { isMetamaskError, isNetworkError, isPasswordPwnedError, + isPasswordUntrustedError, isReverificationCancelledError, isUnauthorizedError, isUserLockedError, diff --git a/packages/shared/src/errors/helpers.ts b/packages/shared/src/errors/helpers.ts index 046270fedf9..943dab42bcf 100644 --- a/packages/shared/src/errors/helpers.ts +++ b/packages/shared/src/errors/helpers.ts @@ -120,6 +120,15 @@ export function isPasswordPwnedError(err: any) { return isClerkAPIResponseError(err) && err.errors?.[0]?.code === 'form_password_pwned'; } +/** + * Checks if the provided error is a clerk api response error indicating a password was pwned. + * + * @internal + */ +export function isPasswordUntrustedError(err: any) { + return isClerkAPIResponseError(err) && err.errors?.[0]?.code === 'form_password_untrusted'; +} + /** * Checks if the provided error is an EmailLinkError. * diff --git a/packages/shared/src/types/localization.ts b/packages/shared/src/types/localization.ts index d46434cc2fe..8c9266d1469 100644 --- a/packages/shared/src/types/localization.ts +++ b/packages/shared/src/types/localization.ts @@ -400,6 +400,9 @@ export type __internal_LocalizationResource = { passwordPwned: { title: LocalizationValue; }; + passwordUntrusted: { + title: LocalizationValue; + }; passkey: { title: LocalizationValue; subtitle: LocalizationValue; From 241595fe78452c997f197e2d803d9e7d8627edcf Mon Sep 17 00:00:00 2001 From: Vaggelis Yfantis Date: Wed, 19 Nov 2025 13:11:46 +0200 Subject: [PATCH 11/29] feat(clerk-js): Initial work for reset password task --- packages/localizations/src/en-US.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/localizations/src/en-US.ts b/packages/localizations/src/en-US.ts index 99d4822c1ce..54ea56b1dab 100644 --- a/packages/localizations/src/en-US.ts +++ b/packages/localizations/src/en-US.ts @@ -694,6 +694,9 @@ export const enUS: LocalizationResource = { passwordPwned: { title: 'Password compromised', }, + passwordUntrusted: { + title: 'Password untrusted', + }, phoneCode: { formTitle: 'Verification code', resendButton: "Didn't receive a code? Resend", From a11f2fc6156edded6f1c06dc6d508853db5fe11e Mon Sep 17 00:00:00 2001 From: Vaggelis Yfantis Date: Thu, 20 Nov 2025 15:44:04 +0200 Subject: [PATCH 12/29] revert(clerk-js): Remove the logic for sign-in error on untrusted password --- .../SignIn/SignInFactorOnePasswordCard.tsx | 21 ++++++------------- packages/shared/src/error.ts | 1 - 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/packages/clerk-js/src/ui/components/SignIn/SignInFactorOnePasswordCard.tsx b/packages/clerk-js/src/ui/components/SignIn/SignInFactorOnePasswordCard.tsx index 93c0d910035..f7e05371cee 100644 --- a/packages/clerk-js/src/ui/components/SignIn/SignInFactorOnePasswordCard.tsx +++ b/packages/clerk-js/src/ui/components/SignIn/SignInFactorOnePasswordCard.tsx @@ -1,4 +1,4 @@ -import { isPasswordPwnedError, isPasswordUntrustedError, isUserLockedError } from '@clerk/shared/error'; +import { isPasswordPwnedError, isUserLockedError } from '@clerk/shared/error'; import { useClerk } from '@clerk/shared/react'; import React from 'react'; @@ -21,7 +21,7 @@ import { useResetPasswordFactor } from './useResetPasswordFactor'; type SignInFactorOnePasswordProps = { onForgotPasswordMethodClick: React.MouseEventHandler | undefined; onShowAlternativeMethodsClick: React.MouseEventHandler | undefined; - onUntrustedPassword?: (errorCode: string) => void; + onPasswordPwned?: () => void; }; const usePasswordControl = (props: SignInFactorOnePasswordProps) => { @@ -50,7 +50,7 @@ const usePasswordControl = (props: SignInFactorOnePasswordProps) => { }; export const SignInFactorOnePasswordCard = (props: SignInFactorOnePasswordProps) => { - const { onShowAlternativeMethodsClick, onUntrustedPassword } = props; + const { onShowAlternativeMethodsClick, onPasswordPwned } = props; const passwordInputRef = React.useRef(null); const card = useCardState(); const { setActive } = useClerk(); @@ -92,18 +92,9 @@ export const SignInFactorOnePasswordCard = (props: SignInFactorOnePasswordProps) return clerk.__internal_navigateWithError('..', err.errors[0]); } - if (onUntrustedPassword) { - // TODO(vaggelis): those will eventually be unified into a single error code - if (isPasswordPwnedError(err)) { - card.setError({ ...err.errors[0], code: 'form_password_pwned__sign_in' }); - onUntrustedPassword('form_password_pwned__sign_in'); - return; - } - if (isPasswordUntrustedError(err)) { - card.setError({ ...err.errors[0], code: 'form_password_untrusted__sign_in' }); - onUntrustedPassword('form_password_untrusted__sign_in'); - return; - } + if (isPasswordPwnedError(err) && onPasswordPwned) { + card.setError({ ...err.errors[0], code: 'form_password_pwned__sign_in' }); + onPasswordPwned(); return; } diff --git a/packages/shared/src/error.ts b/packages/shared/src/error.ts index 2e9b9293866..14b32870d1f 100644 --- a/packages/shared/src/error.ts +++ b/packages/shared/src/error.ts @@ -24,7 +24,6 @@ export { isMetamaskError, isNetworkError, isPasswordPwnedError, - isPasswordUntrustedError, isReverificationCancelledError, isUnauthorizedError, isUserLockedError, From ab06c2b7c3aed4d96f716c296ffdd361997be924 Mon Sep 17 00:00:00 2001 From: Vaggelis Yfantis Date: Thu, 20 Nov 2025 19:53:20 +0200 Subject: [PATCH 13/29] refactor(localization): Remove 'passwordUntrusted' key from en-US localization files --- packages/localizations/src/en-US.ts | 3 --- packages/shared/src/types/localization.ts | 3 --- 2 files changed, 6 deletions(-) diff --git a/packages/localizations/src/en-US.ts b/packages/localizations/src/en-US.ts index 54ea56b1dab..99d4822c1ce 100644 --- a/packages/localizations/src/en-US.ts +++ b/packages/localizations/src/en-US.ts @@ -694,9 +694,6 @@ export const enUS: LocalizationResource = { passwordPwned: { title: 'Password compromised', }, - passwordUntrusted: { - title: 'Password untrusted', - }, phoneCode: { formTitle: 'Verification code', resendButton: "Didn't receive a code? Resend", diff --git a/packages/shared/src/types/localization.ts b/packages/shared/src/types/localization.ts index 8c9266d1469..d46434cc2fe 100644 --- a/packages/shared/src/types/localization.ts +++ b/packages/shared/src/types/localization.ts @@ -400,9 +400,6 @@ export type __internal_LocalizationResource = { passwordPwned: { title: LocalizationValue; }; - passwordUntrusted: { - title: LocalizationValue; - }; passkey: { title: LocalizationValue; subtitle: LocalizationValue; From 04a782428677ae1d18f6cf5f8551bfed807d3aed Mon Sep 17 00:00:00 2001 From: Laura Beatris <48022589+LauraBeatris@users.noreply.github.com> Date: Wed, 26 Nov 2025 18:49:59 -0300 Subject: [PATCH 14/29] Fix navigation to n+1 task within modal --- .../tasks/TaskResetPassword/withTaskGuard.ts | 26 ------------------- 1 file changed, 26 deletions(-) delete mode 100644 packages/clerk-js/src/ui/components/SessionTasks/tasks/TaskResetPassword/withTaskGuard.ts diff --git a/packages/clerk-js/src/ui/components/SessionTasks/tasks/TaskResetPassword/withTaskGuard.ts b/packages/clerk-js/src/ui/components/SessionTasks/tasks/TaskResetPassword/withTaskGuard.ts deleted file mode 100644 index b145ef6c292..00000000000 --- a/packages/clerk-js/src/ui/components/SessionTasks/tasks/TaskResetPassword/withTaskGuard.ts +++ /dev/null @@ -1,26 +0,0 @@ -import type { ComponentType } from 'react'; - -import { warnings } from '@/core/warnings'; -import { withRedirect } from '@/ui/common'; -import { useTaskResetPasswordContext } from '@/ui/contexts/components/SessionTasks'; -import type { AvailableComponentProps } from '@/ui/types'; - -export const withTaskGuard =

(Component: ComponentType

) => { - const displayName = Component.displayName || Component.name || 'Component'; - Component.displayName = displayName; - - const HOC = (props: P) => { - const ctx = useTaskResetPasswordContext(); - return withRedirect( - Component, - clerk => !clerk.session?.currentTask || clerk.session.currentTask.key !== 'reset-password', - ({ clerk }) => - !clerk.session ? clerk.buildSignInUrl() : (ctx.redirectUrlComplete ?? clerk.buildAfterSignInUrl()), - warnings.cannotRenderComponentWhenTaskDoesNotExist, - )(props); - }; - - HOC.displayName = `withTaskGuard(${displayName})`; - - return HOC; -}; From 44cfbc8c543a48e935de489b61b5f976f8b54ddb Mon Sep 17 00:00:00 2001 From: Vaggelis Yfantis Date: Fri, 28 Nov 2025 01:38:25 +0200 Subject: [PATCH 15/29] fix(clerk-js): Update token handling in Session class to ensure correct token is emitted on updates --- packages/clerk-js/src/core/resources/Session.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/clerk-js/src/core/resources/Session.ts b/packages/clerk-js/src/core/resources/Session.ts index ee5df2c43a1..6aba92a59e3 100644 --- a/packages/clerk-js/src/core/resources/Session.ts +++ b/packages/clerk-js/src/core/resources/Session.ts @@ -377,11 +377,17 @@ export class Session extends BaseResource implements SessionResource { 'session', ); const cachedToken = await cachedEntry.tokenResolver; + const isCacheTokenDifferent = + this.lastActiveToken && this.lastActiveToken.getRawString() !== cachedToken.getRawString(); + + const token = isCacheTokenDifferent ? this.lastActiveToken : cachedToken; + if (shouldDispatchTokenUpdate) { - eventBus.emit(events.TokenUpdate, { token: cachedToken }); + eventBus.emit(events.TokenUpdate, { token }); } + // Return null when raw string is empty to indicate that there it's signed-out - return cachedToken.getRawString() || null; + return token?.getRawString() || cachedToken.getRawString() || null; } debugLogger.info( From 2f34a1c5230caffa022a53f66313e12256ba84dd Mon Sep 17 00:00:00 2001 From: Vaggelis Yfantis Date: Fri, 28 Nov 2025 11:56:11 +0200 Subject: [PATCH 16/29] fix(clerk-js): Enhance token resolve to ensure accurate token retrieval and caching --- .../clerk-js/src/core/resources/Session.ts | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/packages/clerk-js/src/core/resources/Session.ts b/packages/clerk-js/src/core/resources/Session.ts index 6aba92a59e3..9fbb1a3afd2 100644 --- a/packages/clerk-js/src/core/resources/Session.ts +++ b/packages/clerk-js/src/core/resources/Session.ts @@ -377,17 +377,29 @@ export class Session extends BaseResource implements SessionResource { 'session', ); const cachedToken = await cachedEntry.tokenResolver; - const isCacheTokenDifferent = - this.lastActiveToken && this.lastActiveToken.getRawString() !== cachedToken.getRawString(); - - const token = isCacheTokenDifferent ? this.lastActiveToken : cachedToken; + const cachedTokenIat = cachedToken.jwt?.claims?.iat || 0; + const lastActiveAtTokenIat = this.lastActiveToken?.jwt?.claims?.iat || 0; + const isLastActiveTokenTheSameAsCached = this.lastActiveToken?.id === cachedToken.id; + const isLastActiveIssuedAfterCached = + this.lastActiveToken && isLastActiveTokenTheSameAsCached && lastActiveAtTokenIat >= cachedTokenIat; + + // If the last active token is the same as the cached token and is issued after the cached token, update the cache with the last active token + if (isLastActiveIssuedAfterCached && this.lastActiveToken) { + SessionTokenCache.set({ tokenId, tokenResolver: new Promise(() => this.lastActiveToken) }); + } if (shouldDispatchTokenUpdate) { - eventBus.emit(events.TokenUpdate, { token }); + eventBus.emit(events.TokenUpdate, { + token: isLastActiveIssuedAfterCached ? this.lastActiveToken : cachedToken, + }); + } + + if (isLastActiveIssuedAfterCached && this.lastActiveToken) { + return this.lastActiveToken.getRawString() || null; } // Return null when raw string is empty to indicate that there it's signed-out - return token?.getRawString() || cachedToken.getRawString() || null; + return cachedToken.getRawString() || null; } debugLogger.info( From 424b1aa973bf687afc9dc19ffeb40916f055a70d Mon Sep 17 00:00:00 2001 From: Vaggelis Yfantis Date: Fri, 28 Nov 2025 12:01:01 +0200 Subject: [PATCH 17/29] fix(clerk-js): Update token caching to use Promise.resolve for last active token --- packages/clerk-js/src/core/resources/Session.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/clerk-js/src/core/resources/Session.ts b/packages/clerk-js/src/core/resources/Session.ts index 9fbb1a3afd2..bea6beacfd4 100644 --- a/packages/clerk-js/src/core/resources/Session.ts +++ b/packages/clerk-js/src/core/resources/Session.ts @@ -385,7 +385,7 @@ export class Session extends BaseResource implements SessionResource { // If the last active token is the same as the cached token and is issued after the cached token, update the cache with the last active token if (isLastActiveIssuedAfterCached && this.lastActiveToken) { - SessionTokenCache.set({ tokenId, tokenResolver: new Promise(() => this.lastActiveToken) }); + SessionTokenCache.set({ tokenId, tokenResolver: Promise.resolve(this.lastActiveToken) }); } if (shouldDispatchTokenUpdate) { From 3eb3c673b45258374ee7fb7360c10a5d2f9a8a4e Mon Sep 17 00:00:00 2001 From: Vaggelis Yfantis Date: Fri, 28 Nov 2025 15:54:23 +0200 Subject: [PATCH 18/29] revert changes --- packages/clerk-js/src/core/resources/Session.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/clerk-js/src/core/resources/Session.ts b/packages/clerk-js/src/core/resources/Session.ts index bea6beacfd4..787f46c86aa 100644 --- a/packages/clerk-js/src/core/resources/Session.ts +++ b/packages/clerk-js/src/core/resources/Session.ts @@ -397,7 +397,6 @@ export class Session extends BaseResource implements SessionResource { if (isLastActiveIssuedAfterCached && this.lastActiveToken) { return this.lastActiveToken.getRawString() || null; } - // Return null when raw string is empty to indicate that there it's signed-out return cachedToken.getRawString() || null; } From 098dde8c83bec31af9042daf65dc5ae5ee93c889 Mon Sep 17 00:00:00 2001 From: Vaggelis Yfantis Date: Fri, 28 Nov 2025 21:38:17 +0200 Subject: [PATCH 19/29] chore: Remove stale changes --- .changeset/yummy-geese-work.md | 5 ----- packages/clerk-js/src/core/resources/Session.ts | 17 +---------------- packages/react/src/isomorphicClerk.ts | 4 ++-- packages/shared/src/types/clerk.ts | 2 +- 4 files changed, 4 insertions(+), 24 deletions(-) delete mode 100644 .changeset/yummy-geese-work.md diff --git a/.changeset/yummy-geese-work.md b/.changeset/yummy-geese-work.md deleted file mode 100644 index 7388c6df720..00000000000 --- a/.changeset/yummy-geese-work.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@clerk/clerk-react': minor ---- - -Expose `buildTasksUrl` parameters diff --git a/packages/clerk-js/src/core/resources/Session.ts b/packages/clerk-js/src/core/resources/Session.ts index 787f46c86aa..a6196189264 100644 --- a/packages/clerk-js/src/core/resources/Session.ts +++ b/packages/clerk-js/src/core/resources/Session.ts @@ -377,26 +377,11 @@ export class Session extends BaseResource implements SessionResource { 'session', ); const cachedToken = await cachedEntry.tokenResolver; - const cachedTokenIat = cachedToken.jwt?.claims?.iat || 0; - const lastActiveAtTokenIat = this.lastActiveToken?.jwt?.claims?.iat || 0; - const isLastActiveTokenTheSameAsCached = this.lastActiveToken?.id === cachedToken.id; - const isLastActiveIssuedAfterCached = - this.lastActiveToken && isLastActiveTokenTheSameAsCached && lastActiveAtTokenIat >= cachedTokenIat; - - // If the last active token is the same as the cached token and is issued after the cached token, update the cache with the last active token - if (isLastActiveIssuedAfterCached && this.lastActiveToken) { - SessionTokenCache.set({ tokenId, tokenResolver: Promise.resolve(this.lastActiveToken) }); - } - if (shouldDispatchTokenUpdate) { eventBus.emit(events.TokenUpdate, { - token: isLastActiveIssuedAfterCached ? this.lastActiveToken : cachedToken, + token: cachedToken, }); } - - if (isLastActiveIssuedAfterCached && this.lastActiveToken) { - return this.lastActiveToken.getRawString() || null; - } // Return null when raw string is empty to indicate that there it's signed-out return cachedToken.getRawString() || null; } diff --git a/packages/react/src/isomorphicClerk.ts b/packages/react/src/isomorphicClerk.ts index f50686702fe..fc8b450987f 100644 --- a/packages/react/src/isomorphicClerk.ts +++ b/packages/react/src/isomorphicClerk.ts @@ -404,8 +404,8 @@ export class IsomorphicClerk implements IsomorphicLoadedClerk { } }; - buildTasksUrl = (opts?: TasksRedirectOptions): string | void => { - const callback = () => this.clerkjs?.buildTasksUrl(opts) || ''; + buildTasksUrl = (): string | void => { + const callback = () => this.clerkjs?.buildTasksUrl() || ''; if (this.clerkjs && this.loaded) { return callback(); } else { diff --git a/packages/shared/src/types/clerk.ts b/packages/shared/src/types/clerk.ts index 6f49b6289ea..84e3b5832b6 100644 --- a/packages/shared/src/types/clerk.ts +++ b/packages/shared/src/types/clerk.ts @@ -744,7 +744,7 @@ export interface Clerk { /** * Returns the configured url where tasks are mounted. */ - buildTasksUrl(opts?: TasksRedirectOptions): string; + buildTasksUrl(): string; /** * Returns the configured afterSignInUrl of the instance. From 2e495fa2c80776fd7e6b03aed0d148fb78297ec3 Mon Sep 17 00:00:00 2001 From: Vaggelis Yfantis Date: Fri, 28 Nov 2025 21:39:06 +0200 Subject: [PATCH 20/29] chore: Remove stale changes --- packages/clerk-js/src/core/resources/Session.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/clerk-js/src/core/resources/Session.ts b/packages/clerk-js/src/core/resources/Session.ts index a6196189264..ee5df2c43a1 100644 --- a/packages/clerk-js/src/core/resources/Session.ts +++ b/packages/clerk-js/src/core/resources/Session.ts @@ -378,9 +378,7 @@ export class Session extends BaseResource implements SessionResource { ); const cachedToken = await cachedEntry.tokenResolver; if (shouldDispatchTokenUpdate) { - eventBus.emit(events.TokenUpdate, { - token: cachedToken, - }); + eventBus.emit(events.TokenUpdate, { token: cachedToken }); } // Return null when raw string is empty to indicate that there it's signed-out return cachedToken.getRawString() || null; From 7328287de3f541843e6f793ec85fdc523f2b8cb6 Mon Sep 17 00:00:00 2001 From: Vaggelis Yfantis Date: Fri, 28 Nov 2025 21:41:00 +0200 Subject: [PATCH 21/29] fix(localization,shared): Add localization types --- packages/localizations/src/en-GB.ts | 3 --- packages/shared/src/types/localization.ts | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/localizations/src/en-GB.ts b/packages/localizations/src/en-GB.ts index 1854dbb1afc..1192dfecc62 100644 --- a/packages/localizations/src/en-GB.ts +++ b/packages/localizations/src/en-GB.ts @@ -697,9 +697,6 @@ export const enGB: LocalizationResource = { passwordPwned: { title: 'Password compromised', }, - passwordUntrusted: { - title: 'Password compromised', - }, phoneCode: { formTitle: 'Verification code', resendButton: "Didn't receive a code? Resend", diff --git a/packages/shared/src/types/localization.ts b/packages/shared/src/types/localization.ts index d46434cc2fe..8c9266d1469 100644 --- a/packages/shared/src/types/localization.ts +++ b/packages/shared/src/types/localization.ts @@ -400,6 +400,9 @@ export type __internal_LocalizationResource = { passwordPwned: { title: LocalizationValue; }; + passwordUntrusted: { + title: LocalizationValue; + }; passkey: { title: LocalizationValue; subtitle: LocalizationValue; From 648a4b126c5b2c0360acf5f692eb1f50fd4c58e2 Mon Sep 17 00:00:00 2001 From: Vaggelis Yfantis Date: Fri, 28 Nov 2025 22:13:27 +0200 Subject: [PATCH 22/29] fix(clerk-js,shared): Export and use isPasswordUntrustedError --- .../SignIn/SignInFactorOnePasswordCard.tsx | 32 ++++++++++++------- packages/shared/src/error.ts | 1 + 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/packages/clerk-js/src/ui/components/SignIn/SignInFactorOnePasswordCard.tsx b/packages/clerk-js/src/ui/components/SignIn/SignInFactorOnePasswordCard.tsx index f7e05371cee..33ab6c12194 100644 --- a/packages/clerk-js/src/ui/components/SignIn/SignInFactorOnePasswordCard.tsx +++ b/packages/clerk-js/src/ui/components/SignIn/SignInFactorOnePasswordCard.tsx @@ -1,4 +1,4 @@ -import { isPasswordPwnedError, isUserLockedError } from '@clerk/shared/error'; +import { isPasswordPwnedError, isPasswordUntrustedError, isUserLockedError } from '@clerk/shared/error'; import { useClerk } from '@clerk/shared/react'; import React from 'react'; @@ -21,7 +21,7 @@ import { useResetPasswordFactor } from './useResetPasswordFactor'; type SignInFactorOnePasswordProps = { onForgotPasswordMethodClick: React.MouseEventHandler | undefined; onShowAlternativeMethodsClick: React.MouseEventHandler | undefined; - onPasswordPwned?: () => void; + onUntrustedPassword?: (errorCode: string) => void; }; const usePasswordControl = (props: SignInFactorOnePasswordProps) => { @@ -50,7 +50,7 @@ const usePasswordControl = (props: SignInFactorOnePasswordProps) => { }; export const SignInFactorOnePasswordCard = (props: SignInFactorOnePasswordProps) => { - const { onShowAlternativeMethodsClick, onPasswordPwned } = props; + const { onShowAlternativeMethodsClick, onUntrustedPassword } = props; const passwordInputRef = React.useRef(null); const card = useCardState(); const { setActive } = useClerk(); @@ -64,20 +64,20 @@ export const SignInFactorOnePasswordCard = (props: SignInFactorOnePasswordProps) const clerk = useClerk(); const goBack = () => { - return navigate('../'); + void navigate('../'); }; - const handlePasswordSubmit: React.FormEventHandler = async e => { + const handlePasswordSubmit: React.FormEventHandler = e => { e.preventDefault(); - return signIn + void signIn .attemptFirstFactor({ strategy: 'password', password: passwordControl.value }) .then(res => { switch (res.status) { case 'complete': return setActive({ session: res.createdSessionId, - navigate: async ({ session }) => { - await navigateOnSetActive({ session, redirectUrl: afterSignInUrl }); + navigate: ({ session }) => { + void navigateOnSetActive({ session, redirectUrl: afterSignInUrl }); }, }); case 'needs_second_factor': @@ -92,10 +92,18 @@ export const SignInFactorOnePasswordCard = (props: SignInFactorOnePasswordProps) return clerk.__internal_navigateWithError('..', err.errors[0]); } - if (isPasswordPwnedError(err) && onPasswordPwned) { - card.setError({ ...err.errors[0], code: 'form_password_pwned__sign_in' }); - onPasswordPwned(); - return; + if (onUntrustedPassword) { + if (isPasswordPwnedError(err)) { + card.setError({ ...err.errors[0], code: 'form_password_pwned__sign_in' }); + onUntrustedPassword('form_password_pwned__sign_in'); + return; + } + + if (isPasswordUntrustedError(err)) { + card.setError({ ...err.errors[0], code: 'form_password_untrusted__sign_in' }); + onUntrustedPassword('form_password_untrusted__sign_in'); + return; + } } handleError(err, [passwordControl], card.setError); diff --git a/packages/shared/src/error.ts b/packages/shared/src/error.ts index 14b32870d1f..2e9b9293866 100644 --- a/packages/shared/src/error.ts +++ b/packages/shared/src/error.ts @@ -24,6 +24,7 @@ export { isMetamaskError, isNetworkError, isPasswordPwnedError, + isPasswordUntrustedError, isReverificationCancelledError, isUnauthorizedError, isUserLockedError, From 399c05a249f894296e7ff66295ec12fd25b8126b Mon Sep 17 00:00:00 2001 From: Vaggelis Yfantis Date: Fri, 28 Nov 2025 22:15:48 +0200 Subject: [PATCH 23/29] fix(localization): Add en-US localization --- packages/localizations/src/en-US.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/localizations/src/en-US.ts b/packages/localizations/src/en-US.ts index 99d4822c1ce..2a955c190a1 100644 --- a/packages/localizations/src/en-US.ts +++ b/packages/localizations/src/en-US.ts @@ -694,6 +694,9 @@ export const enUS: LocalizationResource = { passwordPwned: { title: 'Password compromised', }, + passwordUntrusted: { + title: 'Password compromised', + }, phoneCode: { formTitle: 'Verification code', resendButton: "Didn't receive a code? Resend", From 4d6536f27297d5d3056426db5f6e1f672bbbc2f3 Mon Sep 17 00:00:00 2001 From: Vaggelis Yfantis Date: Sat, 29 Nov 2025 02:46:41 +0200 Subject: [PATCH 24/29] chore(repo): Add changeset --- .changeset/sweet-poets-sell.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changeset/sweet-poets-sell.md diff --git a/.changeset/sweet-poets-sell.md b/.changeset/sweet-poets-sell.md new file mode 100644 index 00000000000..15328c03b8b --- /dev/null +++ b/.changeset/sweet-poets-sell.md @@ -0,0 +1,7 @@ +--- +'@clerk/localizations': minor +'@clerk/clerk-js': minor +'@clerk/shared': minor +--- + +Introduce a new variant for the alternative methods screen to handle untrusted password error on sign-in From e35238edff036a1ef49164020fc22c04a8fd3619 Mon Sep 17 00:00:00 2001 From: Vaggelis Yfantis Date: Sun, 30 Nov 2025 16:32:24 +0200 Subject: [PATCH 25/29] tests(clerk-js): Add unit test for untrusted password screen --- .../SignIn/__tests__/SignInFactorOne.test.tsx | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/packages/clerk-js/src/ui/components/SignIn/__tests__/SignInFactorOne.test.tsx b/packages/clerk-js/src/ui/components/SignIn/__tests__/SignInFactorOne.test.tsx index d610e2d9150..bfb23b8187a 100644 --- a/packages/clerk-js/src/ui/components/SignIn/__tests__/SignInFactorOne.test.tsx +++ b/packages/clerk-js/src/ui/components/SignIn/__tests__/SignInFactorOne.test.tsx @@ -1003,4 +1003,89 @@ describe('SignInFactorOne', () => { }); }); }); + + describe('Password untrusted', () => { + it('it shows the untrusted password screen if the users password is untrusted', async () => { + const { wrapper, fixtures } = await createFixtures(f => { + f.withEmailAddress(); + f.withPassword(); + f.withPreferredSignInStrategy({ strategy: 'password' }); + f.withSocialProvider({ provider: 'google', authenticatable: true }); + f.startSignInWithEmailAddress({ + supportEmailCode: true, + supportPassword: true, + supportResetPassword: true, + }); + }); + fixtures.signIn.prepareFirstFactor.mockReturnValueOnce(Promise.resolve({} as SignInResource)); + + const errJSON = { + code: 'form_password_untrusted', + long_message: + "Your appears to have been compromised or it's no longer trusted and cannot be used. Please use another method to continue.", + message: + "Your appears to have been compromised or it's no longer trusted and cannot be used. Please use another method to continue.", + meta: { param_name: 'password' }, + }; + + fixtures.signIn.attemptFirstFactor.mockRejectedValueOnce( + new ClerkAPIResponseError('Error', { + data: [errJSON], + status: 422, + }), + ); + const { userEvent } = render(, { wrapper }); + await userEvent.type(screen.getByLabelText('Password'), '123456'); + await userEvent.click(screen.getByText('Continue')); + + await screen.findByText('Password compromised'); + await screen.findByText( + "Your appears to have been compromised or it's no longer trusted and cannot be used. Please use another method to continue.", + ); + + await screen.findByText('Email code to hello@clerk.com'); + await screen.findByText('Continue with Google'); + }); + + it('clicking the email code method should prompt the user to verify their email', async () => { + const { wrapper, fixtures } = await createFixtures(f => { + f.withEmailAddress(); + f.withPassword(); + f.withPreferredSignInStrategy({ strategy: 'password' }); + f.withSocialProvider({ provider: 'google', authenticatable: true }); + f.startSignInWithEmailAddress({ + supportEmailCode: true, + supportPassword: true, + supportResetPassword: true, + supportEmailLink: true, + }); + }); + fixtures.signIn.prepareFirstFactor.mockReturnValueOnce(Promise.resolve({} as SignInResource)); + + const errJSON = { + code: 'form_password_untrusted', + long_message: + "Your appears to have been compromised or it's no longer trusted and cannot be used. Please use another method to continue.", + message: + "Your appears to have been compromised or it's no longer trusted and cannot be used. Please use another method to continue.", + meta: { param_name: 'password' }, + }; + + fixtures.signIn.attemptFirstFactor.mockRejectedValueOnce( + new ClerkAPIResponseError('Error', { + data: [errJSON], + status: 422, + }), + ); + const { userEvent, debug } = render(, { wrapper }); + await userEvent.type(screen.getByLabelText('Password'), '123456'); + await userEvent.click(screen.getByText('Continue')); + + console.log(debug()); + + await screen.findByText('Password compromised'); + await userEvent.click(screen.getByText('Email code to hello@clerk.com')); + await screen.findByText('Check your email'); + }); + }); }); From 149237a6d130da0f5dbac1f777423d3c12a0ad23 Mon Sep 17 00:00:00 2001 From: Vaggelis Yfantis Date: Sun, 30 Nov 2025 16:56:53 +0200 Subject: [PATCH 26/29] chore: Remove console.log from tests --- .../ui/components/SignIn/__tests__/SignInFactorOne.test.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/clerk-js/src/ui/components/SignIn/__tests__/SignInFactorOne.test.tsx b/packages/clerk-js/src/ui/components/SignIn/__tests__/SignInFactorOne.test.tsx index bfb23b8187a..0900d0b2c82 100644 --- a/packages/clerk-js/src/ui/components/SignIn/__tests__/SignInFactorOne.test.tsx +++ b/packages/clerk-js/src/ui/components/SignIn/__tests__/SignInFactorOne.test.tsx @@ -1077,12 +1077,10 @@ describe('SignInFactorOne', () => { status: 422, }), ); - const { userEvent, debug } = render(, { wrapper }); + const { userEvent } = render(, { wrapper }); await userEvent.type(screen.getByLabelText('Password'), '123456'); await userEvent.click(screen.getByText('Continue')); - console.log(debug()); - await screen.findByText('Password compromised'); await userEvent.click(screen.getByText('Email code to hello@clerk.com')); await screen.findByText('Check your email'); From 6655eb5aee1347635c228341d775fdec3211c6a8 Mon Sep 17 00:00:00 2001 From: Vaggelis Yfantis Date: Mon, 1 Dec 2025 11:57:51 +0200 Subject: [PATCH 27/29] feat(localizations): Generate all localizations --- .../SignIn/__tests__/SignInFactorOne.test.tsx | 161 +++++++++--------- packages/localizations/src/ar-SA.ts | 3 + packages/localizations/src/be-BY.ts | 3 + packages/localizations/src/bg-BG.ts | 3 + packages/localizations/src/bn-IN.ts | 3 + packages/localizations/src/ca-ES.ts | 3 + packages/localizations/src/cs-CZ.ts | 3 + packages/localizations/src/da-DK.ts | 3 + packages/localizations/src/de-DE.ts | 3 + packages/localizations/src/el-GR.ts | 3 + packages/localizations/src/en-GB.ts | 3 + packages/localizations/src/es-CR.ts | 3 + packages/localizations/src/es-ES.ts | 3 + packages/localizations/src/es-MX.ts | 3 + packages/localizations/src/es-UY.ts | 3 + packages/localizations/src/fa-IR.ts | 3 + packages/localizations/src/fi-FI.ts | 3 + packages/localizations/src/fr-FR.ts | 3 + packages/localizations/src/he-IL.ts | 3 + packages/localizations/src/hi-IN.ts | 3 + packages/localizations/src/hr-HR.ts | 3 + packages/localizations/src/hu-HU.ts | 3 + packages/localizations/src/id-ID.ts | 3 + packages/localizations/src/is-IS.ts | 3 + packages/localizations/src/it-IT.ts | 3 + packages/localizations/src/ja-JP.ts | 3 + packages/localizations/src/kk-KZ.ts | 3 + packages/localizations/src/ko-KR.ts | 3 + packages/localizations/src/mn-MN.ts | 3 + packages/localizations/src/ms-MY.ts | 3 + packages/localizations/src/nb-NO.ts | 3 + packages/localizations/src/nl-BE.ts | 3 + packages/localizations/src/nl-NL.ts | 3 + packages/localizations/src/pl-PL.ts | 3 + packages/localizations/src/pt-BR.ts | 3 + packages/localizations/src/pt-PT.ts | 3 + packages/localizations/src/ro-RO.ts | 3 + packages/localizations/src/ru-RU.ts | 3 + packages/localizations/src/sk-SK.ts | 3 + packages/localizations/src/sr-RS.ts | 3 + packages/localizations/src/sv-SE.ts | 3 + packages/localizations/src/ta-IN.ts | 3 + packages/localizations/src/te-IN.ts | 3 + packages/localizations/src/th-TH.ts | 3 + packages/localizations/src/tr-TR.ts | 3 + packages/localizations/src/uk-UA.ts | 3 + packages/localizations/src/vi-VN.ts | 3 + packages/localizations/src/zh-CN.ts | 3 + packages/localizations/src/zh-TW.ts | 3 + packages/shared/src/errors/helpers.ts | 2 +- 50 files changed, 223 insertions(+), 84 deletions(-) diff --git a/packages/clerk-js/src/ui/components/SignIn/__tests__/SignInFactorOne.test.tsx b/packages/clerk-js/src/ui/components/SignIn/__tests__/SignInFactorOne.test.tsx index 0900d0b2c82..8987451ba97 100644 --- a/packages/clerk-js/src/ui/components/SignIn/__tests__/SignInFactorOne.test.tsx +++ b/packages/clerk-js/src/ui/components/SignIn/__tests__/SignInFactorOne.test.tsx @@ -352,6 +352,84 @@ describe('SignInFactorOne', () => { ), ).not.toBeInTheDocument(); }); + + it('using an untrusted password should show the untrusted password screen', async () => { + const { wrapper, fixtures } = await createFixtures(f => { + f.withEmailAddress(); + f.withPassword(); + f.withPreferredSignInStrategy({ strategy: 'password' }); + f.startSignInWithEmailAddress({ + supportEmailCode: true, + supportPassword: true, + supportResetPassword: true, + }); + }); + fixtures.signIn.prepareFirstFactor.mockReturnValueOnce(Promise.resolve({} as SignInResource)); + + const errJSON = { + code: 'form_password_untrusted', + long_message: + "Your appears to have been compromised or it's no longer trusted and cannot be used. Please use another method to continue.", + message: + "Your appears to have been compromised or it's no longer trusted and cannot be used. Please use another method to continue.", + meta: { param_name: 'password' }, + }; + + fixtures.signIn.attemptFirstFactor.mockRejectedValueOnce( + new ClerkAPIResponseError('Error', { + data: [errJSON], + status: 422, + }), + ); + const { userEvent } = render(, { wrapper }); + await userEvent.type(screen.getByLabelText('Password'), '123456'); + await userEvent.click(screen.getByText('Continue')); + + await screen.findByText('Password compromised'); + await screen.findByText( + "Your appears to have been compromised or it's no longer trusted and cannot be used. Please use another method to continue.", + ); + + await screen.findByText('Email code to hello@clerk.com'); + }); + + it('Prompts the user to use a different method if the password is untrusted', async () => { + const { wrapper, fixtures } = await createFixtures(f => { + f.withEmailAddress(); + f.withPassword(); + f.withPreferredSignInStrategy({ strategy: 'password' }); + f.withSocialProvider({ provider: 'google', authenticatable: true }); + f.startSignInWithEmailAddress({ + supportEmailCode: true, + supportPassword: true, + supportResetPassword: true, + }); + }); + fixtures.signIn.prepareFirstFactor.mockReturnValueOnce(Promise.resolve({} as SignInResource)); + + const errJSON = { + code: 'form_password_untrusted', + long_message: + "Your appears to have been compromised or it's no longer trusted and cannot be used. Please use another method to continue.", + message: + "Your appears to have been compromised or it's no longer trusted and cannot be used. Please use another method to continue.", + meta: { param_name: 'password' }, + }; + + fixtures.signIn.attemptFirstFactor.mockRejectedValueOnce( + new ClerkAPIResponseError('Error', { + data: [errJSON], + status: 422, + }), + ); + const { userEvent } = render(, { wrapper }); + await userEvent.type(screen.getByLabelText('Password'), '123456'); + await userEvent.click(screen.getByText('Continue')); + + await screen.findByText('Password compromised'); + await userEvent.click(screen.getByText('Email code to hello@clerk.com')); + await screen.findByText('Check your email'); + }); }); describe('Forgot Password', () => { @@ -1003,87 +1081,4 @@ describe('SignInFactorOne', () => { }); }); }); - - describe('Password untrusted', () => { - it('it shows the untrusted password screen if the users password is untrusted', async () => { - const { wrapper, fixtures } = await createFixtures(f => { - f.withEmailAddress(); - f.withPassword(); - f.withPreferredSignInStrategy({ strategy: 'password' }); - f.withSocialProvider({ provider: 'google', authenticatable: true }); - f.startSignInWithEmailAddress({ - supportEmailCode: true, - supportPassword: true, - supportResetPassword: true, - }); - }); - fixtures.signIn.prepareFirstFactor.mockReturnValueOnce(Promise.resolve({} as SignInResource)); - - const errJSON = { - code: 'form_password_untrusted', - long_message: - "Your appears to have been compromised or it's no longer trusted and cannot be used. Please use another method to continue.", - message: - "Your appears to have been compromised or it's no longer trusted and cannot be used. Please use another method to continue.", - meta: { param_name: 'password' }, - }; - - fixtures.signIn.attemptFirstFactor.mockRejectedValueOnce( - new ClerkAPIResponseError('Error', { - data: [errJSON], - status: 422, - }), - ); - const { userEvent } = render(, { wrapper }); - await userEvent.type(screen.getByLabelText('Password'), '123456'); - await userEvent.click(screen.getByText('Continue')); - - await screen.findByText('Password compromised'); - await screen.findByText( - "Your appears to have been compromised or it's no longer trusted and cannot be used. Please use another method to continue.", - ); - - await screen.findByText('Email code to hello@clerk.com'); - await screen.findByText('Continue with Google'); - }); - - it('clicking the email code method should prompt the user to verify their email', async () => { - const { wrapper, fixtures } = await createFixtures(f => { - f.withEmailAddress(); - f.withPassword(); - f.withPreferredSignInStrategy({ strategy: 'password' }); - f.withSocialProvider({ provider: 'google', authenticatable: true }); - f.startSignInWithEmailAddress({ - supportEmailCode: true, - supportPassword: true, - supportResetPassword: true, - supportEmailLink: true, - }); - }); - fixtures.signIn.prepareFirstFactor.mockReturnValueOnce(Promise.resolve({} as SignInResource)); - - const errJSON = { - code: 'form_password_untrusted', - long_message: - "Your appears to have been compromised or it's no longer trusted and cannot be used. Please use another method to continue.", - message: - "Your appears to have been compromised or it's no longer trusted and cannot be used. Please use another method to continue.", - meta: { param_name: 'password' }, - }; - - fixtures.signIn.attemptFirstFactor.mockRejectedValueOnce( - new ClerkAPIResponseError('Error', { - data: [errJSON], - status: 422, - }), - ); - const { userEvent } = render(, { wrapper }); - await userEvent.type(screen.getByLabelText('Password'), '123456'); - await userEvent.click(screen.getByText('Continue')); - - await screen.findByText('Password compromised'); - await userEvent.click(screen.getByText('Email code to hello@clerk.com')); - await screen.findByText('Check your email'); - }); - }); }); diff --git a/packages/localizations/src/ar-SA.ts b/packages/localizations/src/ar-SA.ts index 0a6eb8fc297..2c2d7473d80 100644 --- a/packages/localizations/src/ar-SA.ts +++ b/packages/localizations/src/ar-SA.ts @@ -693,6 +693,9 @@ export const arSA: LocalizationResource = { passwordPwned: { title: 'كلمة المرور غير آمنة', }, + passwordUntrusted: { + title: undefined, + }, phoneCode: { formTitle: 'رمز التحقق', resendButton: 'لم يصلك الرمز؟ حاول مرة أخرى', diff --git a/packages/localizations/src/be-BY.ts b/packages/localizations/src/be-BY.ts index 5edf1b0be0e..29ad7fa4f1e 100644 --- a/packages/localizations/src/be-BY.ts +++ b/packages/localizations/src/be-BY.ts @@ -700,6 +700,9 @@ export const beBY: LocalizationResource = { passwordPwned: { title: 'Пароль быў узламаны', }, + passwordUntrusted: { + title: undefined, + }, phoneCode: { formTitle: 'Код верыфікацыі', resendButton: 'Пераадправіць код', diff --git a/packages/localizations/src/bg-BG.ts b/packages/localizations/src/bg-BG.ts index fd25218bd00..a4a0bf4e702 100644 --- a/packages/localizations/src/bg-BG.ts +++ b/packages/localizations/src/bg-BG.ts @@ -696,6 +696,9 @@ export const bgBG: LocalizationResource = { passwordPwned: { title: undefined, }, + passwordUntrusted: { + title: undefined, + }, phoneCode: { formTitle: 'Код за потвърждение', resendButton: 'Не сте получили код? Изпрати отново', diff --git a/packages/localizations/src/bn-IN.ts b/packages/localizations/src/bn-IN.ts index db7f5bf7119..e4f285010b9 100644 --- a/packages/localizations/src/bn-IN.ts +++ b/packages/localizations/src/bn-IN.ts @@ -699,6 +699,9 @@ export const bnIN: LocalizationResource = { passwordPwned: { title: 'পাসওয়ার্ড সমঝোতা হয়েছে', }, + passwordUntrusted: { + title: undefined, + }, phoneCode: { formTitle: 'যাচাইকরণ কোড', resendButton: 'কোনো কোড পাননি? পুনরায় পাঠান', diff --git a/packages/localizations/src/ca-ES.ts b/packages/localizations/src/ca-ES.ts index 4c13f615ded..9bc7e3424a0 100644 --- a/packages/localizations/src/ca-ES.ts +++ b/packages/localizations/src/ca-ES.ts @@ -696,6 +696,9 @@ export const caES: LocalizationResource = { passwordPwned: { title: undefined, }, + passwordUntrusted: { + title: undefined, + }, phoneCode: { formTitle: 'Codi de verificació', resendButton: 'No has rebut el codi? Reenvia', diff --git a/packages/localizations/src/cs-CZ.ts b/packages/localizations/src/cs-CZ.ts index 8386a17118a..565b63abe2f 100644 --- a/packages/localizations/src/cs-CZ.ts +++ b/packages/localizations/src/cs-CZ.ts @@ -704,6 +704,9 @@ export const csCZ: LocalizationResource = { passwordPwned: { title: 'Heslo kompromitováno', }, + passwordUntrusted: { + title: undefined, + }, phoneCode: { formTitle: 'Ověřovací kód', resendButton: 'Neobdrželi jste kód? Znovu poslat', diff --git a/packages/localizations/src/da-DK.ts b/packages/localizations/src/da-DK.ts index 55ab3213d53..453a4b3ff8c 100644 --- a/packages/localizations/src/da-DK.ts +++ b/packages/localizations/src/da-DK.ts @@ -695,6 +695,9 @@ export const daDK: LocalizationResource = { passwordPwned: { title: 'Sikkerhedsadvarsel', }, + passwordUntrusted: { + title: undefined, + }, phoneCode: { formTitle: 'Bekræftelseskode', resendButton: 'Send kode igen', diff --git a/packages/localizations/src/de-DE.ts b/packages/localizations/src/de-DE.ts index d27ff2c5c4f..d22b7e475e9 100644 --- a/packages/localizations/src/de-DE.ts +++ b/packages/localizations/src/de-DE.ts @@ -709,6 +709,9 @@ export const deDE: LocalizationResource = { passwordPwned: { title: 'Passwort kompromittiert', }, + passwordUntrusted: { + title: undefined, + }, phoneCode: { formTitle: 'Bestätigungscode', resendButton: 'Code erneut senden', diff --git a/packages/localizations/src/el-GR.ts b/packages/localizations/src/el-GR.ts index ef6df79a222..835d3557a7f 100644 --- a/packages/localizations/src/el-GR.ts +++ b/packages/localizations/src/el-GR.ts @@ -697,6 +697,9 @@ export const elGR: LocalizationResource = { passwordPwned: { title: 'Παραβιασμένος κωδικός', }, + passwordUntrusted: { + title: undefined, + }, phoneCode: { formTitle: 'Κωδικός επαλήθευσης', resendButton: 'Δεν λάβατε κωδικό; Αποστολή ξανά', diff --git a/packages/localizations/src/en-GB.ts b/packages/localizations/src/en-GB.ts index 1192dfecc62..19aef90e9d4 100644 --- a/packages/localizations/src/en-GB.ts +++ b/packages/localizations/src/en-GB.ts @@ -697,6 +697,9 @@ export const enGB: LocalizationResource = { passwordPwned: { title: 'Password compromised', }, + passwordUntrusted: { + title: undefined, + }, phoneCode: { formTitle: 'Verification code', resendButton: "Didn't receive a code? Resend", diff --git a/packages/localizations/src/es-CR.ts b/packages/localizations/src/es-CR.ts index 1c8d4a6293a..756c93d2022 100644 --- a/packages/localizations/src/es-CR.ts +++ b/packages/localizations/src/es-CR.ts @@ -701,6 +701,9 @@ export const esCR: LocalizationResource = { passwordPwned: { title: 'Contraseña en peligro', }, + passwordUntrusted: { + title: undefined, + }, phoneCode: { formTitle: 'Código de verificación', resendButton: 'Reenviar código', diff --git a/packages/localizations/src/es-ES.ts b/packages/localizations/src/es-ES.ts index 8e414f8962d..f0e67de4f12 100644 --- a/packages/localizations/src/es-ES.ts +++ b/packages/localizations/src/es-ES.ts @@ -697,6 +697,9 @@ export const esES: LocalizationResource = { passwordPwned: { title: 'Tu contraseña ha sido comprometida', }, + passwordUntrusted: { + title: undefined, + }, phoneCode: { formTitle: 'Código de verificación', resendButton: 'Reenviar código', diff --git a/packages/localizations/src/es-MX.ts b/packages/localizations/src/es-MX.ts index 9a6b8749924..8454011b686 100644 --- a/packages/localizations/src/es-MX.ts +++ b/packages/localizations/src/es-MX.ts @@ -702,6 +702,9 @@ export const esMX: LocalizationResource = { passwordPwned: { title: 'Contraseña en peligro', }, + passwordUntrusted: { + title: undefined, + }, phoneCode: { formTitle: 'Código de verificación', resendButton: 'Reenviar código', diff --git a/packages/localizations/src/es-UY.ts b/packages/localizations/src/es-UY.ts index 0e35a91ff85..809c13e85cf 100644 --- a/packages/localizations/src/es-UY.ts +++ b/packages/localizations/src/es-UY.ts @@ -700,6 +700,9 @@ export const esUY: LocalizationResource = { passwordPwned: { title: 'Contraseña comprometida', }, + passwordUntrusted: { + title: undefined, + }, phoneCode: { formTitle: 'Código de verificación', resendButton: '¿No recibiste un código? Reenviar', diff --git a/packages/localizations/src/fa-IR.ts b/packages/localizations/src/fa-IR.ts index 3d96cb2db32..ed34fb70f02 100644 --- a/packages/localizations/src/fa-IR.ts +++ b/packages/localizations/src/fa-IR.ts @@ -705,6 +705,9 @@ export const faIR: LocalizationResource = { passwordPwned: { title: 'رمز عبور به خطر افتاده است', }, + passwordUntrusted: { + title: undefined, + }, phoneCode: { formTitle: 'کد تأیید', resendButton: 'کدی دریافت نکردید؟ ارسال دوباره', diff --git a/packages/localizations/src/fi-FI.ts b/packages/localizations/src/fi-FI.ts index cbedb7e1ba5..2228f316517 100644 --- a/packages/localizations/src/fi-FI.ts +++ b/packages/localizations/src/fi-FI.ts @@ -697,6 +697,9 @@ export const fiFI: LocalizationResource = { passwordPwned: { title: 'Salasana kompromisoitu', }, + passwordUntrusted: { + title: undefined, + }, phoneCode: { formTitle: 'Vahvistuskoodi', resendButton: 'Etkö saanut koodia? Lähetä uudelleen', diff --git a/packages/localizations/src/fr-FR.ts b/packages/localizations/src/fr-FR.ts index ce67548eab6..fb6bca83516 100644 --- a/packages/localizations/src/fr-FR.ts +++ b/packages/localizations/src/fr-FR.ts @@ -710,6 +710,9 @@ export const frFR: LocalizationResource = { passwordPwned: { title: 'Mot de passe compromis', }, + passwordUntrusted: { + title: undefined, + }, phoneCode: { formTitle: 'Code de vérification', resendButton: "Vous n'avez pas reçu de code ? Renvoyer", diff --git a/packages/localizations/src/he-IL.ts b/packages/localizations/src/he-IL.ts index ebb1f905732..f2d69725dd0 100644 --- a/packages/localizations/src/he-IL.ts +++ b/packages/localizations/src/he-IL.ts @@ -688,6 +688,9 @@ export const heIL: LocalizationResource = { passwordPwned: { title: undefined, }, + passwordUntrusted: { + title: undefined, + }, phoneCode: { formTitle: 'קוד אימות', resendButton: 'שלח את הקוד שוב', diff --git a/packages/localizations/src/hi-IN.ts b/packages/localizations/src/hi-IN.ts index 91b3bfb24b7..f1026af2bb1 100644 --- a/packages/localizations/src/hi-IN.ts +++ b/packages/localizations/src/hi-IN.ts @@ -698,6 +698,9 @@ export const hiIN: LocalizationResource = { passwordPwned: { title: 'पासवर्ड समझौता हो गया', }, + passwordUntrusted: { + title: undefined, + }, phoneCode: { formTitle: 'सत्यापन कोड', resendButton: 'कोड नहीं मिला? फिर से भेजें', diff --git a/packages/localizations/src/hr-HR.ts b/packages/localizations/src/hr-HR.ts index 7a2410446b4..15155f057ff 100644 --- a/packages/localizations/src/hr-HR.ts +++ b/packages/localizations/src/hr-HR.ts @@ -697,6 +697,9 @@ export const hrHR: LocalizationResource = { passwordPwned: { title: 'Lozinka je kompromitirana', }, + passwordUntrusted: { + title: undefined, + }, phoneCode: { formTitle: 'Verifikacijski kod', resendButton: 'Niste primili kod? Pošalji ponovno', diff --git a/packages/localizations/src/hu-HU.ts b/packages/localizations/src/hu-HU.ts index 3b4ad30f8dc..8e0cb9e6713 100644 --- a/packages/localizations/src/hu-HU.ts +++ b/packages/localizations/src/hu-HU.ts @@ -696,6 +696,9 @@ export const huHU: LocalizationResource = { passwordPwned: { title: 'Jelszó kompromitálódott', }, + passwordUntrusted: { + title: undefined, + }, phoneCode: { formTitle: 'Visszaigazoló kód', resendButton: 'Nem kaptad meg a kódot? Újraküldés', diff --git a/packages/localizations/src/id-ID.ts b/packages/localizations/src/id-ID.ts index 7328c119fce..09c506acd68 100644 --- a/packages/localizations/src/id-ID.ts +++ b/packages/localizations/src/id-ID.ts @@ -699,6 +699,9 @@ export const idID: LocalizationResource = { passwordPwned: { title: 'Kata sandi terkompromi', }, + passwordUntrusted: { + title: undefined, + }, phoneCode: { formTitle: 'Kode verifikasi', resendButton: 'Tidak menerima kode? Kirim ulang', diff --git a/packages/localizations/src/is-IS.ts b/packages/localizations/src/is-IS.ts index 6473e293d9f..b53f2f8a235 100644 --- a/packages/localizations/src/is-IS.ts +++ b/packages/localizations/src/is-IS.ts @@ -698,6 +698,9 @@ export const isIS: LocalizationResource = { passwordPwned: { title: 'Lykilorð brotið', }, + passwordUntrusted: { + title: undefined, + }, phoneCode: { formTitle: 'Staðfestingarkóði', resendButton: 'Fékkstu ekki kóða? Senda aftur', diff --git a/packages/localizations/src/it-IT.ts b/packages/localizations/src/it-IT.ts index a03c0d84b4a..02a37aa9f8b 100644 --- a/packages/localizations/src/it-IT.ts +++ b/packages/localizations/src/it-IT.ts @@ -703,6 +703,9 @@ export const itIT: LocalizationResource = { passwordPwned: { title: 'La tua password è stata trovata in un data breach.', }, + passwordUntrusted: { + title: undefined, + }, phoneCode: { formTitle: 'Codice di verifica', resendButton: 'Rinvia il codice', diff --git a/packages/localizations/src/ja-JP.ts b/packages/localizations/src/ja-JP.ts index ae34ed69d28..423e89da682 100644 --- a/packages/localizations/src/ja-JP.ts +++ b/packages/localizations/src/ja-JP.ts @@ -706,6 +706,9 @@ export const jaJP: LocalizationResource = { passwordPwned: { title: 'パスワードが漏えいしました', }, + passwordUntrusted: { + title: undefined, + }, phoneCode: { formTitle: '検証コード', resendButton: 'コードを再送信', diff --git a/packages/localizations/src/kk-KZ.ts b/packages/localizations/src/kk-KZ.ts index 6459c076f80..963905854ff 100644 --- a/packages/localizations/src/kk-KZ.ts +++ b/packages/localizations/src/kk-KZ.ts @@ -688,6 +688,9 @@ export const kkKZ: LocalizationResource = { passwordPwned: { title: 'Құпия сөз қауіпті', }, + passwordUntrusted: { + title: undefined, + }, phoneCode: { formTitle: 'Растау коды', resendButton: 'Код алмадыңыз ба? Қайта жіберу', diff --git a/packages/localizations/src/ko-KR.ts b/packages/localizations/src/ko-KR.ts index 12a8d878ae5..bc5245c8e20 100644 --- a/packages/localizations/src/ko-KR.ts +++ b/packages/localizations/src/ko-KR.ts @@ -690,6 +690,9 @@ export const koKR: LocalizationResource = { passwordPwned: { title: undefined, }, + passwordUntrusted: { + title: undefined, + }, phoneCode: { formTitle: '인증 코드', resendButton: '코드 다시 보내기', diff --git a/packages/localizations/src/mn-MN.ts b/packages/localizations/src/mn-MN.ts index 7ca05237166..d9ece66474d 100644 --- a/packages/localizations/src/mn-MN.ts +++ b/packages/localizations/src/mn-MN.ts @@ -697,6 +697,9 @@ export const mnMN: LocalizationResource = { passwordPwned: { title: undefined, }, + passwordUntrusted: { + title: undefined, + }, phoneCode: { formTitle: 'Баталгаажуулах код', resendButton: 'Код хүлээж аваагүй юу? Дахин илгээх', diff --git a/packages/localizations/src/ms-MY.ts b/packages/localizations/src/ms-MY.ts index c5384fe4599..e3c3af85def 100644 --- a/packages/localizations/src/ms-MY.ts +++ b/packages/localizations/src/ms-MY.ts @@ -701,6 +701,9 @@ export const msMY: LocalizationResource = { passwordPwned: { title: 'Kata laluan dikompromi', }, + passwordUntrusted: { + title: undefined, + }, phoneCode: { formTitle: 'Kod pengesahan', resendButton: 'Tidak menerima kod? Hantar semula', diff --git a/packages/localizations/src/nb-NO.ts b/packages/localizations/src/nb-NO.ts index 1bf6fea355c..e77c2193627 100644 --- a/packages/localizations/src/nb-NO.ts +++ b/packages/localizations/src/nb-NO.ts @@ -695,6 +695,9 @@ export const nbNO: LocalizationResource = { passwordPwned: { title: undefined, }, + passwordUntrusted: { + title: undefined, + }, phoneCode: { formTitle: 'Verifiseringskode', resendButton: 'Send kode på nytt', diff --git a/packages/localizations/src/nl-BE.ts b/packages/localizations/src/nl-BE.ts index 8cb1fc8774f..ebb0ae2b71a 100644 --- a/packages/localizations/src/nl-BE.ts +++ b/packages/localizations/src/nl-BE.ts @@ -696,6 +696,9 @@ export const nlBE: LocalizationResource = { passwordPwned: { title: 'Dit wachtwoord is gelekt bij een datalek. Kies een ander wachtwoord om veiligheidsredenen.', }, + passwordUntrusted: { + title: undefined, + }, phoneCode: { formTitle: 'Verificatiecode', resendButton: 'Verstuur code opnieuw', diff --git a/packages/localizations/src/nl-NL.ts b/packages/localizations/src/nl-NL.ts index 519917a2083..cffb0d24e70 100644 --- a/packages/localizations/src/nl-NL.ts +++ b/packages/localizations/src/nl-NL.ts @@ -696,6 +696,9 @@ export const nlNL: LocalizationResource = { passwordPwned: { title: 'Dit wachtwoord is gelekt bij een datalek. Kies een ander wachtwoord om veiligheidsredenen.', }, + passwordUntrusted: { + title: undefined, + }, phoneCode: { formTitle: 'Verificatiecode', resendButton: 'Verstuur code opnieuw', diff --git a/packages/localizations/src/pl-PL.ts b/packages/localizations/src/pl-PL.ts index 4170b27d3fc..b1ee32a8406 100644 --- a/packages/localizations/src/pl-PL.ts +++ b/packages/localizations/src/pl-PL.ts @@ -698,6 +698,9 @@ export const plPL: LocalizationResource = { passwordPwned: { title: 'Hasło skompromitowane', }, + passwordUntrusted: { + title: undefined, + }, phoneCode: { formTitle: 'Kod weryfikacyjny', resendButton: 'Wyślij kod ponownie', diff --git a/packages/localizations/src/pt-BR.ts b/packages/localizations/src/pt-BR.ts index ae36e3b5258..abc8bac69d0 100644 --- a/packages/localizations/src/pt-BR.ts +++ b/packages/localizations/src/pt-BR.ts @@ -705,6 +705,9 @@ export const ptBR: LocalizationResource = { passwordPwned: { title: 'Senha comprometida', }, + passwordUntrusted: { + title: undefined, + }, phoneCode: { formTitle: 'Código de verificação', resendButton: 'Reenviar código', diff --git a/packages/localizations/src/pt-PT.ts b/packages/localizations/src/pt-PT.ts index c05a1ee72cb..b49c013e444 100644 --- a/packages/localizations/src/pt-PT.ts +++ b/packages/localizations/src/pt-PT.ts @@ -694,6 +694,9 @@ export const ptPT: LocalizationResource = { passwordPwned: { title: 'Este password foi comprometido em uma violação de dados. Escolha outro por motivos de segurança.', }, + passwordUntrusted: { + title: undefined, + }, phoneCode: { formTitle: 'Código de verificação', resendButton: 'Reenviar código', diff --git a/packages/localizations/src/ro-RO.ts b/packages/localizations/src/ro-RO.ts index 1d392bfd07e..686d4559a55 100644 --- a/packages/localizations/src/ro-RO.ts +++ b/packages/localizations/src/ro-RO.ts @@ -707,6 +707,9 @@ export const roRO: LocalizationResource = { passwordPwned: { title: 'Parola este compromisă', }, + passwordUntrusted: { + title: undefined, + }, phoneCode: { formTitle: 'Cod de verificare', resendButton: 'Nu ai primit un cod? Retrimite', diff --git a/packages/localizations/src/ru-RU.ts b/packages/localizations/src/ru-RU.ts index 4db50c8da5f..d3df3210eb9 100644 --- a/packages/localizations/src/ru-RU.ts +++ b/packages/localizations/src/ru-RU.ts @@ -705,6 +705,9 @@ export const ruRU: LocalizationResource = { passwordPwned: { title: 'Пароль скомпрометирован', }, + passwordUntrusted: { + title: undefined, + }, phoneCode: { formTitle: 'Верификационный код', resendButton: 'Не получили код? Отправить снова.', diff --git a/packages/localizations/src/sk-SK.ts b/packages/localizations/src/sk-SK.ts index e2029436627..b0064aa2464 100644 --- a/packages/localizations/src/sk-SK.ts +++ b/packages/localizations/src/sk-SK.ts @@ -698,6 +698,9 @@ export const skSK: LocalizationResource = { passwordPwned: { title: undefined, }, + passwordUntrusted: { + title: undefined, + }, phoneCode: { formTitle: 'Overovací kód', resendButton: 'Znova odoslať kód', diff --git a/packages/localizations/src/sr-RS.ts b/packages/localizations/src/sr-RS.ts index 7329de1f3a1..5d4c0a2af0e 100644 --- a/packages/localizations/src/sr-RS.ts +++ b/packages/localizations/src/sr-RS.ts @@ -695,6 +695,9 @@ export const srRS: LocalizationResource = { passwordPwned: { title: 'Lozinka kompromitovana', }, + passwordUntrusted: { + title: undefined, + }, phoneCode: { formTitle: 'Verifikacioni kod', resendButton: 'Nisi primio kod? Pošalji ponovo', diff --git a/packages/localizations/src/sv-SE.ts b/packages/localizations/src/sv-SE.ts index 2867531242b..0cedb3cd0d4 100644 --- a/packages/localizations/src/sv-SE.ts +++ b/packages/localizations/src/sv-SE.ts @@ -698,6 +698,9 @@ export const svSE: LocalizationResource = { passwordPwned: { title: 'Lösenord är för osäkert', }, + passwordUntrusted: { + title: undefined, + }, phoneCode: { formTitle: 'Verifieringskod', resendButton: 'Skicka koden igen', diff --git a/packages/localizations/src/ta-IN.ts b/packages/localizations/src/ta-IN.ts index 8aca964b379..1c0c76beb54 100644 --- a/packages/localizations/src/ta-IN.ts +++ b/packages/localizations/src/ta-IN.ts @@ -701,6 +701,9 @@ export const taIN: LocalizationResource = { passwordPwned: { title: 'கடவுச்சொல் அபாயத்தில் உள்ளது', }, + passwordUntrusted: { + title: undefined, + }, phoneCode: { formTitle: 'சரிபார்ப்புக் குறியீடு', resendButton: 'குறியீடு கிடைக்கவில்லையா? மீண்டும் அனுப்பு', diff --git a/packages/localizations/src/te-IN.ts b/packages/localizations/src/te-IN.ts index 169be047ce3..014254da936 100644 --- a/packages/localizations/src/te-IN.ts +++ b/packages/localizations/src/te-IN.ts @@ -700,6 +700,9 @@ export const teIN: LocalizationResource = { passwordPwned: { title: 'పాస్‌వర్డ్ ప్రమాదంలో ఉంది', }, + passwordUntrusted: { + title: undefined, + }, phoneCode: { formTitle: 'ధృవీకరణ కోడ్', resendButton: 'కోడ్ అందలేదా? మళ్ళీ పంపండి', diff --git a/packages/localizations/src/th-TH.ts b/packages/localizations/src/th-TH.ts index 2bb86668ef0..29da48df1b8 100644 --- a/packages/localizations/src/th-TH.ts +++ b/packages/localizations/src/th-TH.ts @@ -697,6 +697,9 @@ export const thTH: LocalizationResource = { passwordPwned: { title: 'รหัสผ่านถูกโจรกรรม', }, + passwordUntrusted: { + title: undefined, + }, phoneCode: { formTitle: 'รหัสยืนยัน', resendButton: 'ไม่ได้รับรหัส? ส่งใหม่', diff --git a/packages/localizations/src/tr-TR.ts b/packages/localizations/src/tr-TR.ts index 6536b1f2fd0..6f6d1ae7cb9 100644 --- a/packages/localizations/src/tr-TR.ts +++ b/packages/localizations/src/tr-TR.ts @@ -697,6 +697,9 @@ export const trTR: LocalizationResource = { passwordPwned: { title: 'Şifre ele geçirildi', }, + passwordUntrusted: { + title: undefined, + }, phoneCode: { formTitle: 'Doğrulama kodu', resendButton: 'Kod almadınız mı? Tekrar gönderin', diff --git a/packages/localizations/src/uk-UA.ts b/packages/localizations/src/uk-UA.ts index 7dfcd029b96..35187b8df1a 100644 --- a/packages/localizations/src/uk-UA.ts +++ b/packages/localizations/src/uk-UA.ts @@ -694,6 +694,9 @@ export const ukUA: LocalizationResource = { passwordPwned: { title: undefined, }, + passwordUntrusted: { + title: undefined, + }, phoneCode: { formTitle: 'Код підтвердження', resendButton: 'Не отримали код? повторно відправити', diff --git a/packages/localizations/src/vi-VN.ts b/packages/localizations/src/vi-VN.ts index d51877d4427..ed61396f30a 100644 --- a/packages/localizations/src/vi-VN.ts +++ b/packages/localizations/src/vi-VN.ts @@ -703,6 +703,9 @@ export const viVN: LocalizationResource = { passwordPwned: { title: 'Mật khẩu bị rò rỉ', }, + passwordUntrusted: { + title: undefined, + }, phoneCode: { formTitle: 'Mã xác minh', resendButton: 'Không nhận được mã? Gửi lại', diff --git a/packages/localizations/src/zh-CN.ts b/packages/localizations/src/zh-CN.ts index 9188f86c81a..16b5a39193d 100644 --- a/packages/localizations/src/zh-CN.ts +++ b/packages/localizations/src/zh-CN.ts @@ -684,6 +684,9 @@ export const zhCN: LocalizationResource = { passwordPwned: { title: undefined, }, + passwordUntrusted: { + title: undefined, + }, phoneCode: { formTitle: '验证码', resendButton: '重新发送验证码', diff --git a/packages/localizations/src/zh-TW.ts b/packages/localizations/src/zh-TW.ts index fc9494e24e7..c7c2e8c4799 100644 --- a/packages/localizations/src/zh-TW.ts +++ b/packages/localizations/src/zh-TW.ts @@ -684,6 +684,9 @@ export const zhTW: LocalizationResource = { passwordPwned: { title: undefined, }, + passwordUntrusted: { + title: undefined, + }, phoneCode: { formTitle: '驗證碼', resendButton: '重新傳送驗證碼', diff --git a/packages/shared/src/errors/helpers.ts b/packages/shared/src/errors/helpers.ts index 943dab42bcf..2335b141e25 100644 --- a/packages/shared/src/errors/helpers.ts +++ b/packages/shared/src/errors/helpers.ts @@ -121,7 +121,7 @@ export function isPasswordPwnedError(err: any) { } /** - * Checks if the provided error is a clerk api response error indicating a password was pwned. + * Checks if the provided error is a clerk api response error indicating a password was untrusted. * * @internal */ From 80354572479a0625f2a2d040f4733bb5e28266a0 Mon Sep 17 00:00:00 2001 From: Vaggelis Yfantis Date: Mon, 1 Dec 2025 18:18:31 +0200 Subject: [PATCH 28/29] feat: Update password error handling and localization for untrusted passwords --- .../ui/components/SignIn/SignInFactorOne.tsx | 17 +++++++++-------- .../SignIn/SignInFactorOnePasswordCard.tsx | 12 +++++++----- packages/localizations/src/ar-SA.ts | 1 + packages/localizations/src/be-BY.ts | 1 + packages/localizations/src/bg-BG.ts | 1 + packages/localizations/src/bn-IN.ts | 1 + packages/localizations/src/ca-ES.ts | 1 + packages/localizations/src/cs-CZ.ts | 1 + packages/localizations/src/da-DK.ts | 1 + packages/localizations/src/de-DE.ts | 1 + packages/localizations/src/el-GR.ts | 1 + packages/localizations/src/en-GB.ts | 1 + packages/localizations/src/en-US.ts | 2 ++ packages/localizations/src/es-CR.ts | 1 + packages/localizations/src/es-ES.ts | 1 + packages/localizations/src/es-MX.ts | 1 + packages/localizations/src/es-UY.ts | 1 + packages/localizations/src/fa-IR.ts | 1 + packages/localizations/src/fi-FI.ts | 1 + packages/localizations/src/fr-FR.ts | 1 + packages/localizations/src/he-IL.ts | 1 + packages/localizations/src/hi-IN.ts | 1 + packages/localizations/src/hr-HR.ts | 1 + packages/localizations/src/hu-HU.ts | 1 + packages/localizations/src/id-ID.ts | 1 + packages/localizations/src/is-IS.ts | 1 + packages/localizations/src/it-IT.ts | 1 + packages/localizations/src/ja-JP.ts | 1 + packages/localizations/src/kk-KZ.ts | 1 + packages/localizations/src/ko-KR.ts | 1 + packages/localizations/src/mn-MN.ts | 1 + packages/localizations/src/ms-MY.ts | 1 + packages/localizations/src/nb-NO.ts | 1 + packages/localizations/src/nl-BE.ts | 1 + packages/localizations/src/nl-NL.ts | 1 + packages/localizations/src/pl-PL.ts | 1 + packages/localizations/src/pt-BR.ts | 1 + packages/localizations/src/pt-PT.ts | 1 + packages/localizations/src/ro-RO.ts | 1 + packages/localizations/src/ru-RU.ts | 1 + packages/localizations/src/sk-SK.ts | 1 + packages/localizations/src/sr-RS.ts | 1 + packages/localizations/src/sv-SE.ts | 1 + packages/localizations/src/ta-IN.ts | 1 + packages/localizations/src/te-IN.ts | 1 + packages/localizations/src/th-TH.ts | 1 + packages/localizations/src/tr-TR.ts | 1 + packages/localizations/src/uk-UA.ts | 1 + packages/localizations/src/vi-VN.ts | 1 + packages/localizations/src/zh-CN.ts | 1 + packages/localizations/src/zh-TW.ts | 1 + packages/shared/src/types/localization.ts | 1 + 52 files changed, 67 insertions(+), 13 deletions(-) diff --git a/packages/clerk-js/src/ui/components/SignIn/SignInFactorOne.tsx b/packages/clerk-js/src/ui/components/SignIn/SignInFactorOne.tsx index 16e962ffb19..01eb0c0b14e 100644 --- a/packages/clerk-js/src/ui/components/SignIn/SignInFactorOne.tsx +++ b/packages/clerk-js/src/ui/components/SignIn/SignInFactorOne.tsx @@ -20,6 +20,7 @@ import { SignInFactorOneEmailLinkCard } from './SignInFactorOneEmailLinkCard'; import { SignInFactorOneEnterpriseConnections } from './SignInFactorOneEnterpriseConnections'; import { SignInFactorOneForgotPasswordCard } from './SignInFactorOneForgotPasswordCard'; import { SignInFactorOnePasskey } from './SignInFactorOnePasskey'; +import type { PasswordErrorCode } from './SignInFactorOnePasswordCard'; import { SignInFactorOnePasswordCard } from './SignInFactorOnePasswordCard'; import { SignInFactorOnePhoneCodeCard } from './SignInFactorOnePhoneCodeCard'; import { useResetPasswordFactor } from './useResetPasswordFactor'; @@ -44,17 +45,17 @@ const factorKey = (factor: SignInFactor | null | undefined) => { function determineAlternativeMethodsMode( showForgotPasswordStrategies: boolean, - untrustedPasswordErrorCode: string | null, + passwordErrorCode: PasswordErrorCode | null, ): AlternativeMethodsMode { if (!showForgotPasswordStrategies) { return 'default'; } - if (untrustedPasswordErrorCode === 'form_password_pwned__sign_in') { + if (passwordErrorCode === 'pwned') { return 'pwned'; } - if (untrustedPasswordErrorCode === 'form_password_untrusted__sign_in') { + if (passwordErrorCode === 'untrusted') { return 'passwordUntrusted'; } @@ -104,7 +105,7 @@ function SignInFactorOneInternal(): JSX.Element { const [showForgotPasswordStrategies, setShowForgotPasswordStrategies] = React.useState(false); - const [untrustedPasswordErrorCode, setUntrustedPasswordErrorCode] = React.useState(null); + const [passwordErrorCode, setPasswordErrorCode] = React.useState(null); React.useEffect(() => { if (__internal_setActiveInProgress) { @@ -159,11 +160,11 @@ function SignInFactorOneInternal(): JSX.Element { const toggle = showAllStrategies ? toggleAllStrategies : toggleForgotPasswordStrategies; const backHandler = () => { card.setError(undefined); - setUntrustedPasswordErrorCode(null); + setPasswordErrorCode(null); toggle?.(); }; - const mode = determineAlternativeMethodsMode(showForgotPasswordStrategies, untrustedPasswordErrorCode); + const mode = determineAlternativeMethodsMode(showForgotPasswordStrategies, passwordErrorCode); return ( { - setUntrustedPasswordErrorCode(errorCode); + onPasswordError={errorCode => { + setPasswordErrorCode(errorCode); toggleForgotPasswordStrategies(); }} /> diff --git a/packages/clerk-js/src/ui/components/SignIn/SignInFactorOnePasswordCard.tsx b/packages/clerk-js/src/ui/components/SignIn/SignInFactorOnePasswordCard.tsx index 33ab6c12194..009258e8083 100644 --- a/packages/clerk-js/src/ui/components/SignIn/SignInFactorOnePasswordCard.tsx +++ b/packages/clerk-js/src/ui/components/SignIn/SignInFactorOnePasswordCard.tsx @@ -18,10 +18,12 @@ import { useRouter } from '../../router/RouteContext'; import { HavingTrouble } from './HavingTrouble'; import { useResetPasswordFactor } from './useResetPasswordFactor'; +export type PasswordErrorCode = 'untrusted' | 'pwned'; + type SignInFactorOnePasswordProps = { onForgotPasswordMethodClick: React.MouseEventHandler | undefined; onShowAlternativeMethodsClick: React.MouseEventHandler | undefined; - onUntrustedPassword?: (errorCode: string) => void; + onPasswordError?: (errorCode: PasswordErrorCode) => void; }; const usePasswordControl = (props: SignInFactorOnePasswordProps) => { @@ -50,7 +52,7 @@ const usePasswordControl = (props: SignInFactorOnePasswordProps) => { }; export const SignInFactorOnePasswordCard = (props: SignInFactorOnePasswordProps) => { - const { onShowAlternativeMethodsClick, onUntrustedPassword } = props; + const { onShowAlternativeMethodsClick, onPasswordError } = props; const passwordInputRef = React.useRef(null); const card = useCardState(); const { setActive } = useClerk(); @@ -92,16 +94,16 @@ export const SignInFactorOnePasswordCard = (props: SignInFactorOnePasswordProps) return clerk.__internal_navigateWithError('..', err.errors[0]); } - if (onUntrustedPassword) { + if (onPasswordError) { if (isPasswordPwnedError(err)) { card.setError({ ...err.errors[0], code: 'form_password_pwned__sign_in' }); - onUntrustedPassword('form_password_pwned__sign_in'); + onPasswordError('pwned'); return; } if (isPasswordUntrustedError(err)) { card.setError({ ...err.errors[0], code: 'form_password_untrusted__sign_in' }); - onUntrustedPassword('form_password_untrusted__sign_in'); + onPasswordError('untrusted'); return; } } diff --git a/packages/localizations/src/ar-SA.ts b/packages/localizations/src/ar-SA.ts index 2c2d7473d80..19859a1e91c 100644 --- a/packages/localizations/src/ar-SA.ts +++ b/packages/localizations/src/ar-SA.ts @@ -898,6 +898,7 @@ export const arSA: LocalizationResource = { form_password_pwned__sign_in: 'لا يمكن أستعمال كلمة السر هذه لانها غير أمنة, الرجاء اختيار كلمة مرور أخرى', form_password_size_in_bytes_exceeded: 'تجاوزت كلمة المرور الحد الأقصى للحروف المدخلة, الرجاء أدخال كلمة مرور أقصر أو حذف بعض الأحرف الخاصة', + form_password_untrusted__sign_in: undefined, form_password_validation_failed: 'كلمة مرور خاطئة', form_username_invalid_character: undefined, form_username_invalid_length: undefined, diff --git a/packages/localizations/src/be-BY.ts b/packages/localizations/src/be-BY.ts index 29ad7fa4f1e..5f1d30e64bf 100644 --- a/packages/localizations/src/be-BY.ts +++ b/packages/localizations/src/be-BY.ts @@ -907,6 +907,7 @@ export const beBY: LocalizationResource = { form_password_pwned__sign_in: 'Гэты пароль быў узламаны, калі ласка, абярыце іншы.', form_password_size_in_bytes_exceeded: 'Ваш пароль перавышае максімальна дапушчальнае колькасць байтаў, скараціце яго або выдаліце некаторыя спецыяльныя сімвалы.', + form_password_untrusted__sign_in: undefined, form_password_validation_failed: 'Неверагодны пароль', form_username_invalid_character: 'Імя карыстальніка змяшчае недапушчальныя сімвалы.', form_username_invalid_length: 'Імя карыстальніка павінна быць ад 3 да 50 сімвалаў.', diff --git a/packages/localizations/src/bg-BG.ts b/packages/localizations/src/bg-BG.ts index a4a0bf4e702..d0415c58fff 100644 --- a/packages/localizations/src/bg-BG.ts +++ b/packages/localizations/src/bg-BG.ts @@ -900,6 +900,7 @@ export const bgBG: LocalizationResource = { form_password_pwned: 'Тази парола е компрометирана в изтекли данни. Моля, изберете друга.', form_password_pwned__sign_in: undefined, form_password_size_in_bytes_exceeded: 'Паролата ви е твърде дълга. Моля, съкратете я.', + form_password_untrusted__sign_in: undefined, form_password_validation_failed: 'Невалидна парола.', form_username_invalid_character: 'Потребителското име съдържа невалидни символи.', form_username_invalid_length: 'Потребителското име трябва да бъде между 3 и 256 символа.', diff --git a/packages/localizations/src/bn-IN.ts b/packages/localizations/src/bn-IN.ts index e4f285010b9..3db3c4ab3c1 100644 --- a/packages/localizations/src/bn-IN.ts +++ b/packages/localizations/src/bn-IN.ts @@ -909,6 +909,7 @@ export const bnIN: LocalizationResource = { 'এই পাসওয়ার্ডটি একটি ডেটা লঙ্ঘনের অংশ হিসাবে পাওয়া গেছে এবং ব্যবহার করা যাবে না, দয়া করে আপনার পাসওয়ার্ড রিসেট করুন।', form_password_size_in_bytes_exceeded: 'আপনার পাসওয়ার্ড অনুমোদিত সর্বাধিক বাইট সংখ্যা অতিক্রম করেছে, দয়া করে এটি ছোট করুন বা কিছু বিশেষ অক্ষর সরান।', + form_password_untrusted__sign_in: undefined, form_password_validation_failed: 'ভুল পাসওয়ার্ড', form_username_invalid_character: 'আপনার ব্যবহারকারীর নামে অবৈধ অক্ষর রয়েছে। দয়া করে শুধুমাত্র অক্ষর, সংখ্যা এবং আন্ডারস্কোর ব্যবহার করুন।', diff --git a/packages/localizations/src/ca-ES.ts b/packages/localizations/src/ca-ES.ts index 9bc7e3424a0..86be610b9bb 100644 --- a/packages/localizations/src/ca-ES.ts +++ b/packages/localizations/src/ca-ES.ts @@ -902,6 +902,7 @@ export const caES: LocalizationResource = { form_password_pwned__sign_in: undefined, form_password_size_in_bytes_exceeded: 'La teva contrasenya ha superat el nombre màxim de bytes permesos, si us plau, redueix-la o elimina alguns caràcters especials.', + form_password_untrusted__sign_in: undefined, form_password_validation_failed: 'Contrasenya incorrecta', form_username_invalid_character: "El nom d'usuari conté caràcters no vàlids.", form_username_invalid_length: "El nom d'usuari ha de tenir entre 3 i 50 caràcters.", diff --git a/packages/localizations/src/cs-CZ.ts b/packages/localizations/src/cs-CZ.ts index 565b63abe2f..985c4e13be3 100644 --- a/packages/localizations/src/cs-CZ.ts +++ b/packages/localizations/src/cs-CZ.ts @@ -913,6 +913,7 @@ export const csCZ: LocalizationResource = { 'Toto heslo bylo nalezeno jako součást prolomení a nelze ho použít, prosím resetujte si heslo.', form_password_size_in_bytes_exceeded: 'Vaše heslo překročilo maximální povolený počet bajtů, prosím zkrátit ho nebo odstranit některé speciální znaky.', + form_password_untrusted__sign_in: undefined, form_password_validation_failed: 'Nesprávné heslo', form_username_invalid_character: 'Uživatelské jméno může obsahovat pouze alfanumerické znaky a podtržítka.', form_username_invalid_length: 'Vaše uživatelské jméno musí mít mezi {{min_length}} a {{max_length}} znaky.', diff --git a/packages/localizations/src/da-DK.ts b/packages/localizations/src/da-DK.ts index 453a4b3ff8c..dfb600dd67a 100644 --- a/packages/localizations/src/da-DK.ts +++ b/packages/localizations/src/da-DK.ts @@ -899,6 +899,7 @@ export const daDK: LocalizationResource = { form_password_pwned__sign_in: 'Din adgangskode er blevet kompromitteret, vælg en ny.', form_password_size_in_bytes_exceeded: 'Din adgangskode har overskredet det maksimalt tilladte antal bytes, forkort den eller fjern nogle specialtegn.', + form_password_untrusted__sign_in: undefined, form_password_validation_failed: 'Forkert adgangskode.', form_username_invalid_character: 'Brugernavnet indeholder ugyldige tegn.', form_username_invalid_length: 'Brugernavnet har en ugyldig længde.', diff --git a/packages/localizations/src/de-DE.ts b/packages/localizations/src/de-DE.ts index d22b7e475e9..1bbbe6bb56f 100644 --- a/packages/localizations/src/de-DE.ts +++ b/packages/localizations/src/de-DE.ts @@ -918,6 +918,7 @@ export const deDE: LocalizationResource = { 'Dieses Passwort wurde in einem Datenleck gefunden und kann nicht verwendet werden. Bitte setzen Sie Ihr Passwort zurück.', form_password_size_in_bytes_exceeded: 'Das Passwort hat die maximale Anzahl an Bytes überschritten. Bitte kürzen oder Sonderzeichen entfernen.', + form_password_untrusted__sign_in: undefined, form_password_validation_failed: 'Falsches Passwort.', form_username_invalid_character: 'Der Benutzername enthält ungültige Zeichen. Bitte verwenden Sie nur alphanumerische Zeichen und Unterstriche.', diff --git a/packages/localizations/src/el-GR.ts b/packages/localizations/src/el-GR.ts index 835d3557a7f..6ac6bfbdf30 100644 --- a/packages/localizations/src/el-GR.ts +++ b/packages/localizations/src/el-GR.ts @@ -904,6 +904,7 @@ export const elGR: LocalizationResource = { form_password_pwned__sign_in: undefined, form_password_size_in_bytes_exceeded: 'Ο κωδικός πρόσβασής σας έχει υπερβεί το μέγιστο αριθμό bytes που επιτρέπεται. Παρακαλούμε, συντομεύστε τον ή αφαιρέστε μερικούς ειδικούς χαρακτήρες.', + form_password_untrusted__sign_in: undefined, form_password_validation_failed: 'Λανθασμένος κωδικός', form_username_invalid_character: undefined, form_username_invalid_length: undefined, diff --git a/packages/localizations/src/en-GB.ts b/packages/localizations/src/en-GB.ts index 19aef90e9d4..1c8b30b7fc0 100644 --- a/packages/localizations/src/en-GB.ts +++ b/packages/localizations/src/en-GB.ts @@ -905,6 +905,7 @@ export const enGB: LocalizationResource = { 'This password has been found as part of a breach and can not be used, please reset your password.', form_password_size_in_bytes_exceeded: 'Your password has exceeded the maximum number of bytes allowed, please shorten it or remove some special characters.', + form_password_untrusted__sign_in: undefined, form_password_validation_failed: 'Incorrect Password', form_username_invalid_character: 'Your username contains invalid characters. Please use only letters, numbers, and underscores.', diff --git a/packages/localizations/src/en-US.ts b/packages/localizations/src/en-US.ts index 2a955c190a1..27de1a3dfef 100644 --- a/packages/localizations/src/en-US.ts +++ b/packages/localizations/src/en-US.ts @@ -900,6 +900,8 @@ export const enUS: LocalizationResource = { form_password_pwned__sign_in: 'This password has been found as part of a breach and can not be used, please reset your password.', form_password_size_in_bytes_exceeded: undefined, + form_password_untrusted__sign_in: + "Your password appears to have been compromised or it's no longer trusted and cannot be used. Please use another method to continue.", form_password_validation_failed: undefined, form_username_invalid_character: undefined, form_username_invalid_length: 'Your username must be between {{min_length}} and {{max_length}} characters long.', diff --git a/packages/localizations/src/es-CR.ts b/packages/localizations/src/es-CR.ts index 756c93d2022..a22ab47023c 100644 --- a/packages/localizations/src/es-CR.ts +++ b/packages/localizations/src/es-CR.ts @@ -910,6 +910,7 @@ export const esCR: LocalizationResource = { 'Esta contraseña se encontró como parte de una brecha y no se puede utilizar, por favor restablece tu contraseña.', form_password_size_in_bytes_exceeded: 'La contraseña excede el número máximo de bytes permitidos. Por favor, elimine algunos caracteres especiales o reduzca la longitud de la contraseña.', + form_password_untrusted__sign_in: undefined, form_password_validation_failed: 'Contraseña incorrecta', form_username_invalid_character: 'El nombre de usuario contiene caracteres inválidos.', form_username_invalid_length: 'La longitud del nombre de usuario es demasiado corta.', diff --git a/packages/localizations/src/es-ES.ts b/packages/localizations/src/es-ES.ts index f0e67de4f12..8cff58a1a19 100644 --- a/packages/localizations/src/es-ES.ts +++ b/packages/localizations/src/es-ES.ts @@ -903,6 +903,7 @@ export const esES: LocalizationResource = { form_password_pwned__sign_in: 'La contraseña ya está en uso en otro servicio.', form_password_size_in_bytes_exceeded: 'Tu contraseña ha excedido el número máximo de bytes permitidos, por favor acórtala o elimina algunos caracteres especiales.', + form_password_untrusted__sign_in: undefined, form_password_validation_failed: 'La validación de la contraseña falló.', form_username_invalid_character: 'El nombre de usuario contiene caracteres inválidos.', form_username_invalid_length: 'El nombre de usuario debe tener entre 3 y 20 caracteres.', diff --git a/packages/localizations/src/es-MX.ts b/packages/localizations/src/es-MX.ts index 8454011b686..7650fc1065a 100644 --- a/packages/localizations/src/es-MX.ts +++ b/packages/localizations/src/es-MX.ts @@ -911,6 +911,7 @@ export const esMX: LocalizationResource = { 'Esta contraseña se encontró como parte de una brecha y no se puede utilizar, por favor restablece tu contraseña.', form_password_size_in_bytes_exceeded: 'La contraseña excede el número máximo de bytes permitidos. Por favor, elimine algunos caracteres especiales o reduzca la longitud de la contraseña.', + form_password_untrusted__sign_in: undefined, form_password_validation_failed: 'Contraseña incorrecta', form_username_invalid_character: 'El nombre de usuario contiene caracteres inválidos.', form_username_invalid_length: 'La longitud del nombre de usuario es demasiado corta.', diff --git a/packages/localizations/src/es-UY.ts b/packages/localizations/src/es-UY.ts index 809c13e85cf..b3afe7799b9 100644 --- a/packages/localizations/src/es-UY.ts +++ b/packages/localizations/src/es-UY.ts @@ -910,6 +910,7 @@ export const esUY: LocalizationResource = { 'Esta contraseña se encontró en una filtración y no se puede usar. Por favor, restablecé tu contraseña.', form_password_size_in_bytes_exceeded: 'Tu contraseña ha excedido el número máximo de bytes permitidos. Por favor, acortala o eliminá algunos caracteres especiales.', + form_password_untrusted__sign_in: undefined, form_password_validation_failed: 'Contraseña incorrecta', form_username_invalid_character: 'Tu nombre de usuario contiene caracteres inválidos. Por favor, usá solo letras, números y guiones bajos.', diff --git a/packages/localizations/src/fa-IR.ts b/packages/localizations/src/fa-IR.ts index ed34fb70f02..7b3c63870bc 100644 --- a/packages/localizations/src/fa-IR.ts +++ b/packages/localizations/src/fa-IR.ts @@ -912,6 +912,7 @@ export const faIR: LocalizationResource = { form_password_pwned__sign_in: 'این رمز عبور به عنوان بخشی از یک نقض امنیتی یافت شده و قابل استفاده نیست، لطفاً رمز عبور خود را مجدداً تنظیم کنید.', form_password_size_in_bytes_exceeded: 'رمز عبور خیلی طولانی است.', + form_password_untrusted__sign_in: undefined, form_password_validation_failed: 'اعتبارسنجی رمز عبور ناموفق بود.', form_username_invalid_character: 'نام کاربری شامل کاراکترهای نامعتبر است.', form_username_invalid_length: 'نام کاربری شما باید بین {{min_length}} و {{max_length}} کاراکتر باشد.', diff --git a/packages/localizations/src/fi-FI.ts b/packages/localizations/src/fi-FI.ts index 2228f316517..14da0bb7871 100644 --- a/packages/localizations/src/fi-FI.ts +++ b/packages/localizations/src/fi-FI.ts @@ -902,6 +902,7 @@ export const fiFI: LocalizationResource = { form_password_pwned__sign_in: 'Salasana on ollut osallisena tietovuodossa. Vaihdathan salasanasi.', form_password_size_in_bytes_exceeded: 'Salasanasi on ylittänyt sallitun tavumäärän, lyhennä sitä tai poista joitain erikoismerkkejä.', + form_password_untrusted__sign_in: undefined, form_password_validation_failed: 'Väärä salasana.', form_username_invalid_character: undefined, form_username_invalid_length: undefined, diff --git a/packages/localizations/src/fr-FR.ts b/packages/localizations/src/fr-FR.ts index fb6bca83516..186104acdaf 100644 --- a/packages/localizations/src/fr-FR.ts +++ b/packages/localizations/src/fr-FR.ts @@ -918,6 +918,7 @@ export const frFR: LocalizationResource = { form_password_pwned__sign_in: 'Mot de passe compromis. Veuillez le réinitialiser.', form_password_size_in_bytes_exceeded: "Votre mot de passe a dépassé le nombre maximum d'octets autorisés. Veuillez le raccourcir ou supprimer certains caractères spéciaux.", + form_password_untrusted__sign_in: undefined, form_password_validation_failed: 'Mot de passe incorrect', form_username_invalid_character: "L'identifiant contient des caractères invalides.", form_username_invalid_length: "Le nombre de caractères de l'identifiant est invalide.", diff --git a/packages/localizations/src/he-IL.ts b/packages/localizations/src/he-IL.ts index f2d69725dd0..ce3dca3bdc4 100644 --- a/packages/localizations/src/he-IL.ts +++ b/packages/localizations/src/he-IL.ts @@ -891,6 +891,7 @@ export const heIL: LocalizationResource = { 'הסיסמה הזו נמצאה כחלק מהפרטים שנחשפו בהפרת נתונים ולא ניתן להשתמש בה, אנא בצע איתחול לסיסמה שלך.', form_password_size_in_bytes_exceeded: 'הסיסמה שלך חורגת ממספר הבייטים המרבי המותר, נסה לקצר אותה או להסיר כמה תווים מיוחדים.', + form_password_untrusted__sign_in: undefined, form_password_validation_failed: 'סיסמה שגויה', form_username_invalid_character: undefined, form_username_invalid_length: undefined, diff --git a/packages/localizations/src/hi-IN.ts b/packages/localizations/src/hi-IN.ts index f1026af2bb1..3ebf5063509 100644 --- a/packages/localizations/src/hi-IN.ts +++ b/packages/localizations/src/hi-IN.ts @@ -908,6 +908,7 @@ export const hiIN: LocalizationResource = { 'यह पासवर्ड डेटा उल्लंघन के हिस्से के रूप में पाया गया है और इसका उपयोग नहीं किया जा सकता, कृपया अपना पासवर्ड रीसेट करें।', form_password_size_in_bytes_exceeded: 'आपके पासवर्ड ने अनुमत बाइट्स की अधिकतम संख्या से अधिक हो गया है, कृपया इसे छोटा करें या कुछ विशेष वर्णों को हटा दें।', + form_password_untrusted__sign_in: undefined, form_password_validation_failed: 'गलत पासवर्ड', form_username_invalid_character: 'आपके उपयोगकर्ता नाम में अमान्य वर्ण हैं। कृपया केवल अक्षर, संख्या और अंडरस्कोर का उपयोग करें।', diff --git a/packages/localizations/src/hr-HR.ts b/packages/localizations/src/hr-HR.ts index 15155f057ff..0dce556a3a4 100644 --- a/packages/localizations/src/hr-HR.ts +++ b/packages/localizations/src/hr-HR.ts @@ -905,6 +905,7 @@ export const hrHR: LocalizationResource = { 'Ova lozinka je pronađena kao dio curenja podataka i ne može se koristiti, molimo resetirajte svoju lozinku.', form_password_size_in_bytes_exceeded: 'Vaša lozinka je premašila maksimalni dopušteni broj bajtova, molimo skratite je ili uklonite neke posebne znakove.', + form_password_untrusted__sign_in: undefined, form_password_validation_failed: 'Netočna lozinka', form_username_invalid_character: undefined, form_username_invalid_length: undefined, diff --git a/packages/localizations/src/hu-HU.ts b/packages/localizations/src/hu-HU.ts index 8e0cb9e6713..b853cde3c69 100644 --- a/packages/localizations/src/hu-HU.ts +++ b/packages/localizations/src/hu-HU.ts @@ -902,6 +902,7 @@ export const huHU: LocalizationResource = { 'Úgy látjuk, hogy ez a jelszó kiszivárgott, ezért ezt nem használhatod, kérlek állítsd át a jelszavad.', form_password_size_in_bytes_exceeded: 'A jelszavad több bájtot tartalmaz mint a megadott maximum, kérlek rövidítsd vagy törölj ki néhány speciális karaktert.', + form_password_untrusted__sign_in: undefined, form_password_validation_failed: 'Helytelen jelszó', form_username_invalid_character: undefined, form_username_invalid_length: undefined, diff --git a/packages/localizations/src/id-ID.ts b/packages/localizations/src/id-ID.ts index 09c506acd68..68ce2ffdbd0 100644 --- a/packages/localizations/src/id-ID.ts +++ b/packages/localizations/src/id-ID.ts @@ -909,6 +909,7 @@ export const idID: LocalizationResource = { 'Kata sandi ini telah ditemukan sebagai bagian dari kebocoran data dan tidak dapat digunakan, silakan reset kata sandi Anda.', form_password_size_in_bytes_exceeded: 'Kata sandi Anda telah melebihi jumlah byte maksimum yang diizinkan, silakan persingkat atau hapus beberapa karakter khusus.', + form_password_untrusted__sign_in: undefined, form_password_validation_failed: 'Kata Sandi Salah', form_username_invalid_character: undefined, form_username_invalid_length: undefined, diff --git a/packages/localizations/src/is-IS.ts b/packages/localizations/src/is-IS.ts index b53f2f8a235..4063539790e 100644 --- a/packages/localizations/src/is-IS.ts +++ b/packages/localizations/src/is-IS.ts @@ -905,6 +905,7 @@ export const isIS: LocalizationResource = { 'Þetta lykilorð hefur fundist sem hluti af öryggisbresti og má ekki nota, vinsamlegast endurstilltu lykilorðið þitt.', form_password_size_in_bytes_exceeded: 'Lykilorðið þitt hefur farið yfir hámarksfjölda bæta sem leyfðir eru, vinsamlegast styttu það eða fjarlægðu nokkra sérstafi.', + form_password_untrusted__sign_in: undefined, form_password_validation_failed: 'Rangt lykilorð', form_username_invalid_character: undefined, form_username_invalid_length: undefined, diff --git a/packages/localizations/src/it-IT.ts b/packages/localizations/src/it-IT.ts index 02a37aa9f8b..03e0f396884 100644 --- a/packages/localizations/src/it-IT.ts +++ b/packages/localizations/src/it-IT.ts @@ -910,6 +910,7 @@ export const itIT: LocalizationResource = { 'Questa password è stata trovata in una violazione dei dati. Non può essere utilizzata. Reimposta la tua password.', form_password_size_in_bytes_exceeded: 'La tua password ha superato il numero massimo di byte consentiti, per favore accorciala o rimuovi alcuni caratteri speciali.', + form_password_untrusted__sign_in: undefined, form_password_validation_failed: 'Password errata.', form_username_invalid_character: 'Il nome utente contiene caratteri non validi.', form_username_invalid_length: 'Il nome utente deve avere una lunghezza compresa tra 3 e 32 caratteri.', diff --git a/packages/localizations/src/ja-JP.ts b/packages/localizations/src/ja-JP.ts index 423e89da682..cc23d207c3a 100644 --- a/packages/localizations/src/ja-JP.ts +++ b/packages/localizations/src/ja-JP.ts @@ -913,6 +913,7 @@ export const jaJP: LocalizationResource = { form_password_pwned__sign_in: 'このパスワードは侵害の一部として見つかったため使用できません。パスワードをリセットしてください。', form_password_size_in_bytes_exceeded: undefined, + form_password_untrusted__sign_in: undefined, form_password_validation_failed: undefined, form_username_invalid_character: undefined, form_username_invalid_length: 'ユーザー名は{{min_length}}文字以上{{max_length}}文字以下である必要があります。', diff --git a/packages/localizations/src/kk-KZ.ts b/packages/localizations/src/kk-KZ.ts index 963905854ff..446139ed845 100644 --- a/packages/localizations/src/kk-KZ.ts +++ b/packages/localizations/src/kk-KZ.ts @@ -891,6 +891,7 @@ export const kkKZ: LocalizationResource = { form_password_pwned__sign_in: 'Бұл құпия сөз қауіпсіз емес. Құпия сөзді өзгертуге болады.', form_password_size_in_bytes_exceeded: 'Құпия сөзде тым көп байт бар. Оны қысқартыңыз немесе арнайы таңбаларды алып тастаңыз.', + form_password_untrusted__sign_in: undefined, form_password_validation_failed: 'Құпия сөз қате', form_username_invalid_character: 'Пайдаланушы атында жарамсыз таңбалар бар. Тек әріптер, сандар және астыңғы сызықшаларды қолданыңыз.', diff --git a/packages/localizations/src/ko-KR.ts b/packages/localizations/src/ko-KR.ts index bc5245c8e20..dbb1148def4 100644 --- a/packages/localizations/src/ko-KR.ts +++ b/packages/localizations/src/ko-KR.ts @@ -894,6 +894,7 @@ export const koKR: LocalizationResource = { form_password_pwned__sign_in: undefined, form_password_size_in_bytes_exceeded: '비밀번호가 허용되는 최대 바이트 수를 초과했습니다. 비밀번호를 줄이거나 일부 특수 문자를 제거해 주세요.', + form_password_untrusted__sign_in: undefined, form_password_validation_failed: '잘못된 비밀번호', form_username_invalid_character: undefined, form_username_invalid_length: undefined, diff --git a/packages/localizations/src/mn-MN.ts b/packages/localizations/src/mn-MN.ts index d9ece66474d..7336fa7d601 100644 --- a/packages/localizations/src/mn-MN.ts +++ b/packages/localizations/src/mn-MN.ts @@ -902,6 +902,7 @@ export const mnMN: LocalizationResource = { form_password_pwned__sign_in: undefined, form_password_size_in_bytes_exceeded: 'Энэ нууц үгийг зөрчлийн нэг хэсэг гэж олсон тул ашиглах боломжгүй. Өөр нууц үг оруулж үзнэ үү.', + form_password_untrusted__sign_in: undefined, form_password_validation_failed: 'Нууц үг буруу', form_username_invalid_character: 'Хэрэглэгчийн нэр буруу тэмдэгт агуулж байна.', form_username_invalid_length: 'Хэрэглэгчийн нэр буруу байна.', diff --git a/packages/localizations/src/ms-MY.ts b/packages/localizations/src/ms-MY.ts index e3c3af85def..a7307fdefee 100644 --- a/packages/localizations/src/ms-MY.ts +++ b/packages/localizations/src/ms-MY.ts @@ -912,6 +912,7 @@ export const msMY: LocalizationResource = { 'Kata laluan ini telah dijumpai sebagai sebahagian daripada pelanggaran dan tidak boleh digunakan, sila tetapkan semula kata laluan anda.', form_password_size_in_bytes_exceeded: 'Kata laluan anda telah melebihi bilangan maksimum bait yang dibenarkan, sila pendekkannya atau keluarkan beberapa aksara khas.', + form_password_untrusted__sign_in: undefined, form_password_validation_failed: 'Kata Laluan Tidak Betul', form_username_invalid_character: 'Nama pengguna anda mengandungi aksara yang tidak sah. Sila gunakan hanya huruf, nombor, dan garis bawah.', diff --git a/packages/localizations/src/nb-NO.ts b/packages/localizations/src/nb-NO.ts index e77c2193627..3fba1739496 100644 --- a/packages/localizations/src/nb-NO.ts +++ b/packages/localizations/src/nb-NO.ts @@ -901,6 +901,7 @@ export const nbNO: LocalizationResource = { form_password_pwned__sign_in: undefined, form_password_size_in_bytes_exceeded: 'Passordet ditt har overskredet maksimalt antall byte tillatt. Vennligst forkort det eller fjern noen spesialtegn.', + form_password_untrusted__sign_in: undefined, form_password_validation_failed: 'Feil passord', form_username_invalid_character: undefined, form_username_invalid_length: undefined, diff --git a/packages/localizations/src/nl-BE.ts b/packages/localizations/src/nl-BE.ts index ebb0ae2b71a..b74c8dfdb60 100644 --- a/packages/localizations/src/nl-BE.ts +++ b/packages/localizations/src/nl-BE.ts @@ -901,6 +901,7 @@ export const nlBE: LocalizationResource = { form_password_pwned__sign_in: 'Als je dit wachtwoord elders gebruikt, moet je het wijzigen.', form_password_size_in_bytes_exceeded: 'Je wachtwoord heeft het maximum aantal bytes overschreden, vermijd speciale tekens.', + form_password_untrusted__sign_in: undefined, form_password_validation_failed: 'Wachtwoord is incorrect.', form_username_invalid_character: 'De gebruikersnaam bevat ongeldige tekens.', form_username_invalid_length: 'De gebruikersnaam is te kort of te lang.', diff --git a/packages/localizations/src/nl-NL.ts b/packages/localizations/src/nl-NL.ts index cffb0d24e70..f18307a6c37 100644 --- a/packages/localizations/src/nl-NL.ts +++ b/packages/localizations/src/nl-NL.ts @@ -901,6 +901,7 @@ export const nlNL: LocalizationResource = { form_password_pwned__sign_in: 'Als je dit wachtwoord elders gebruikt, moet je het wijzigen.', form_password_size_in_bytes_exceeded: 'Je wachtwoord heeft het maximum aantal bytes overschreden, vermijd speciale tekens.', + form_password_untrusted__sign_in: undefined, form_password_validation_failed: 'Wachtwoord is incorrect.', form_username_invalid_character: 'De gebruikersnaam bevat ongeldige tekens.', form_username_invalid_length: 'De gebruikersnaam is te kort of te lang.', diff --git a/packages/localizations/src/pl-PL.ts b/packages/localizations/src/pl-PL.ts index b1ee32a8406..8c2661f92aa 100644 --- a/packages/localizations/src/pl-PL.ts +++ b/packages/localizations/src/pl-PL.ts @@ -907,6 +907,7 @@ export const plPL: LocalizationResource = { form_password_pwned__sign_in: 'To hasło zostało znalezione w wyniku włamania i nie można go użyć. Zresetuj hasło.', form_password_size_in_bytes_exceeded: 'Twoje hasło przekroczyło maksymalną dozwoloną liczbę bajtów, skróć je lub usuń niektóre znaki specjalne.', + form_password_untrusted__sign_in: undefined, form_password_validation_failed: 'Podane hasło jest nieprawidłowe', form_username_invalid_character: 'Twoja nazwa użytkownika zawiera nieprawidłowe znaki. Prosimy o używanie wyłącznie liter, cyfr i podkreśleń.', diff --git a/packages/localizations/src/pt-BR.ts b/packages/localizations/src/pt-BR.ts index abc8bac69d0..cd5fd52b376 100644 --- a/packages/localizations/src/pt-BR.ts +++ b/packages/localizations/src/pt-BR.ts @@ -913,6 +913,7 @@ export const ptBR: LocalizationResource = { form_password_pwned__sign_in: 'Esta senha foi comprometida, por favor redefina sua senha.', form_password_size_in_bytes_exceeded: 'Sua senha excedeu o número máximo de bytes permitidos, por favor, encurte-a ou remova alguns caracteres especiais.', + form_password_untrusted__sign_in: undefined, form_password_validation_failed: 'Senha incorreta', form_username_invalid_character: 'Nome de usuário contém caracteres inválidos. Por favor, tente outro.', form_username_invalid_length: 'Nome de usuário deve ter entre 3 e 256 caracteres.', diff --git a/packages/localizations/src/pt-PT.ts b/packages/localizations/src/pt-PT.ts index b49c013e444..17e5632c049 100644 --- a/packages/localizations/src/pt-PT.ts +++ b/packages/localizations/src/pt-PT.ts @@ -901,6 +901,7 @@ export const ptPT: LocalizationResource = { 'Esta palavra-passe foi encontrada como parte de uma violação e não pode ser utilizada para login. Por favor, escolha outra.', form_password_size_in_bytes_exceeded: 'A sua palavra-passe excedeu o número máximo de bytes permitidos, por favor, encurte-a ou remova alguns caracteres especiais.', + form_password_untrusted__sign_in: undefined, form_password_validation_failed: 'Falha na validação da palavra-passe.', form_username_invalid_character: 'O nome de utilizador contém caracteres inválidos.', form_username_invalid_length: 'O nome de utilizador deve ter entre 3 e 50 caracteres.', diff --git a/packages/localizations/src/ro-RO.ts b/packages/localizations/src/ro-RO.ts index 686d4559a55..3afc5707b9d 100644 --- a/packages/localizations/src/ro-RO.ts +++ b/packages/localizations/src/ro-RO.ts @@ -914,6 +914,7 @@ export const roRO: LocalizationResource = { form_password_pwned__sign_in: 'Această parolă a fost găsită într-o breșă de securitate și nu poate fi folosită. Te rugăm resetează parola.', form_password_size_in_bytes_exceeded: undefined, + form_password_untrusted__sign_in: undefined, form_password_validation_failed: undefined, form_username_invalid_character: undefined, form_username_invalid_length: diff --git a/packages/localizations/src/ru-RU.ts b/packages/localizations/src/ru-RU.ts index d3df3210eb9..b048a25d7de 100644 --- a/packages/localizations/src/ru-RU.ts +++ b/packages/localizations/src/ru-RU.ts @@ -914,6 +914,7 @@ export const ruRU: LocalizationResource = { 'Этот пароль был найден в утечке данных и не может быть использован. Пожалуйста, сбросьте пароль.', form_password_size_in_bytes_exceeded: 'Ваш пароль превышает максимально допустимое количество байтов, сократите его или удалите некоторые специальные символы.', + form_password_untrusted__sign_in: undefined, form_password_validation_failed: 'Неверный пароль', form_username_invalid_character: undefined, form_username_invalid_length: undefined, diff --git a/packages/localizations/src/sk-SK.ts b/packages/localizations/src/sk-SK.ts index b0064aa2464..c0dddf659b2 100644 --- a/packages/localizations/src/sk-SK.ts +++ b/packages/localizations/src/sk-SK.ts @@ -907,6 +907,7 @@ export const skSK: LocalizationResource = { 'Toto heslo bolo nájdené v rámci úniku dát a nemôže byť použité, prosím zvoľte iné heslo.', form_password_size_in_bytes_exceeded: 'Vaše heslo prekročilo maximálny povolený počet bytov, prosím skráťte ho alebo odstráňte niektoré špeciálne znaky.', + form_password_untrusted__sign_in: undefined, form_password_validation_failed: 'Nesprávne heslo', form_username_invalid_character: 'Používateľské meno môže obsahovať len písmená, číslice, pomlčky a podčiarkovníky.', diff --git a/packages/localizations/src/sr-RS.ts b/packages/localizations/src/sr-RS.ts index 5d4c0a2af0e..a69877be6f8 100644 --- a/packages/localizations/src/sr-RS.ts +++ b/packages/localizations/src/sr-RS.ts @@ -901,6 +901,7 @@ export const srRS: LocalizationResource = { 'Ova lozinka je pronađena kao deo kompromitovanih podataka i ne može se koristiti, molimo resetuj svoju lozinku.', form_password_size_in_bytes_exceeded: 'Tvoja lozinka je premašila maksimalni dozvoljeni broj bajtova, molimo skrati je ili ukloni neke specijalne znakove.', + form_password_untrusted__sign_in: undefined, form_password_validation_failed: 'Neispravna lozinka', form_username_invalid_character: 'Korisničko ime sadrži nevažeće karaktere.', form_username_invalid_length: 'Dužina korisničkog imena nije validna.', diff --git a/packages/localizations/src/sv-SE.ts b/packages/localizations/src/sv-SE.ts index 0cedb3cd0d4..784071272a9 100644 --- a/packages/localizations/src/sv-SE.ts +++ b/packages/localizations/src/sv-SE.ts @@ -904,6 +904,7 @@ export const svSE: LocalizationResource = { form_password_pwned__sign_in: 'Lösenordet har läckt, vänligen logga in för att ändra det.', form_password_size_in_bytes_exceeded: 'Ditt lösenord har överskridit det maximala antalet tillåtna bytes, vänligen förkorta det eller ta bort några specialtecken.', + form_password_untrusted__sign_in: undefined, form_password_validation_failed: 'Felaktigt lösenord', form_username_invalid_character: 'Användarnamnet innehåller ogiltiga tecken.', form_username_invalid_length: 'Användarnamnets längd är ogiltig.', diff --git a/packages/localizations/src/ta-IN.ts b/packages/localizations/src/ta-IN.ts index 1c0c76beb54..2e40dd33cf0 100644 --- a/packages/localizations/src/ta-IN.ts +++ b/packages/localizations/src/ta-IN.ts @@ -911,6 +911,7 @@ export const taIN: LocalizationResource = { 'இந்த கடவுச்சொல் தரவு மீறலின் ஒரு பகுதியாக காணப்பட்டது மற்றும் பயன்படுத்த முடியாது, தயவுசெய்து உங்கள் கடவுச்சொல்லை மீட்டமைக்கவும்.', form_password_size_in_bytes_exceeded: 'உங்கள் கடவுச்சொல் அனுமதிக்கப்பட்ட அதிகபட்ச பைட்டுகளை மீறிவிட்டது, தயவுசெய்து அதை குறைக்கவும் அல்லது சில சிறப்பு எழுத்துக்களை நீக்கவும்.', + form_password_untrusted__sign_in: undefined, form_password_validation_failed: 'தவறான கடவுச்சொல்', form_username_invalid_character: 'உங்கள் பயனர்பெயரில் தவறான எழுத்துக்கள் உள்ளன. எழுத்துக்கள், எண்கள் மற்றும் அடிக்கோடுகளை மட்டும் பயன்படுத்தவும்.', diff --git a/packages/localizations/src/te-IN.ts b/packages/localizations/src/te-IN.ts index 014254da936..508a98b58f0 100644 --- a/packages/localizations/src/te-IN.ts +++ b/packages/localizations/src/te-IN.ts @@ -910,6 +910,7 @@ export const teIN: LocalizationResource = { 'ఈ పాస్‌వర్డ్ డేటా ఉల్లంఘన భాగంగా కనుగొనబడింది మరియు ఉపయోగించడానికి వీలుపడదు, దయచేసి మీ పాస్‌వర్డ్‌ను రీసెట్ చేయండి.', form_password_size_in_bytes_exceeded: 'మీ పాస్‌వర్డ్ అనుమతించిన గరిష్ట బైట్ల సంఖ్యను మించింది, దయచేసి దాన్ని చిన్నదిగా చేయండి లేదా కొన్ని ప్రత్యేక అక్షరాలను తొలగించండి.', + form_password_untrusted__sign_in: undefined, form_password_validation_failed: 'తప్పు పాస్‌వర్డ్', form_username_invalid_character: 'మీ వినియోగదారు పేరులో చెల్లని అక్షరాలు ఉన్నాయి. దయచేసి అక్షరాలు, సంఖ్యలు మరియు అండర్‌స్కోర్‌లను మాత్రమే ఉపయోగించండి.', diff --git a/packages/localizations/src/th-TH.ts b/packages/localizations/src/th-TH.ts index 29da48df1b8..9283b36e026 100644 --- a/packages/localizations/src/th-TH.ts +++ b/packages/localizations/src/th-TH.ts @@ -902,6 +902,7 @@ export const thTH: LocalizationResource = { form_password_pwned__sign_in: 'รหัสผ่านนี้ถูกพบว่าเป็นส่วนหนึ่งของรหัสผ่านที่เคยถูกโจรกรรมข้อมูลและไม่สามารถใช้ได้ โปรดรีเซ็ตรหัสผ่านของคุณ', form_password_size_in_bytes_exceeded: undefined, + form_password_untrusted__sign_in: undefined, form_password_validation_failed: undefined, form_username_invalid_character: undefined, form_username_invalid_length: 'ชื่อผู้ใช้ของคุณต้องมีความยาวระหว่าง {{min_length}} ถึง {{max_length}} ตัวอักษร', diff --git a/packages/localizations/src/tr-TR.ts b/packages/localizations/src/tr-TR.ts index 6f6d1ae7cb9..eb309404ee2 100644 --- a/packages/localizations/src/tr-TR.ts +++ b/packages/localizations/src/tr-TR.ts @@ -903,6 +903,7 @@ export const trTR: LocalizationResource = { 'Bu şifre bir veri ihlalinde tespit edildi ve oturum açmak için kullanılamaz. Lütfen başka bir şifre seçin.', form_password_size_in_bytes_exceeded: 'Şifreniz izin verilen maksimum byte sayısını aştı, lütfen kısaltın veya bazı özel karakterleri çıkarın.', + form_password_untrusted__sign_in: undefined, form_password_validation_failed: 'Şifre doğrulaması başarısız.', form_username_invalid_character: 'Kullanıcı adı geçersiz karakterler içeriyor.', form_username_invalid_length: 'Kullanıcı adı 3 ile 50 karakter arasında olmalıdır.', diff --git a/packages/localizations/src/uk-UA.ts b/packages/localizations/src/uk-UA.ts index 35187b8df1a..9652f3bfe38 100644 --- a/packages/localizations/src/uk-UA.ts +++ b/packages/localizations/src/uk-UA.ts @@ -898,6 +898,7 @@ export const ukUA: LocalizationResource = { form_password_pwned__sign_in: undefined, form_password_size_in_bytes_exceeded: 'Ваш пароль перевищує максимально допустиму кількість байтів, скоротіть його або видаліть деякі спеціальні символи.', + form_password_untrusted__sign_in: undefined, form_password_validation_failed: 'Невірний пароль', form_username_invalid_character: undefined, form_username_invalid_length: undefined, diff --git a/packages/localizations/src/vi-VN.ts b/packages/localizations/src/vi-VN.ts index ed61396f30a..7c45f0702d3 100644 --- a/packages/localizations/src/vi-VN.ts +++ b/packages/localizations/src/vi-VN.ts @@ -909,6 +909,7 @@ export const viVN: LocalizationResource = { form_password_pwned__sign_in: 'Mật khẩu này đã được tìm thấy trong một rò rỉ và không thể được sử dụng, vui lòng đặt lại mật khẩu của bạn.', form_password_size_in_bytes_exceeded: undefined, + form_password_untrusted__sign_in: undefined, form_password_validation_failed: undefined, form_username_invalid_character: undefined, form_username_invalid_length: 'Tên người dùng của bạn phải có giữa {{min_length}} và {{max_length}} ký tự.', diff --git a/packages/localizations/src/zh-CN.ts b/packages/localizations/src/zh-CN.ts index 16b5a39193d..738dda30111 100644 --- a/packages/localizations/src/zh-CN.ts +++ b/packages/localizations/src/zh-CN.ts @@ -885,6 +885,7 @@ export const zhCN: LocalizationResource = { form_password_pwned: '这个密码在数据泄露中被发现,不能使用,请换一个密码试试。', form_password_pwned__sign_in: undefined, form_password_size_in_bytes_exceeded: '您的密码超过了允许的最大字节数,请缩短它或去掉一些特殊字符。', + form_password_untrusted__sign_in: undefined, form_password_validation_failed: '密码错误', form_username_invalid_character: undefined, form_username_invalid_length: undefined, diff --git a/packages/localizations/src/zh-TW.ts b/packages/localizations/src/zh-TW.ts index c7c2e8c4799..58a2dc52599 100644 --- a/packages/localizations/src/zh-TW.ts +++ b/packages/localizations/src/zh-TW.ts @@ -886,6 +886,7 @@ export const zhTW: LocalizationResource = { form_password_pwned: '此密碼已在已知的資料外洩事件中出現,請改用其他密碼。', form_password_pwned__sign_in: undefined, form_password_size_in_bytes_exceeded: '您的密碼超過允許的大小上限,請縮短或移除部分特殊字元。', + form_password_untrusted__sign_in: undefined, form_password_validation_failed: '密碼驗證失敗', form_username_invalid_character: undefined, form_username_invalid_length: undefined, diff --git a/packages/shared/src/types/localization.ts b/packages/shared/src/types/localization.ts index 8c9266d1469..1342f4b97b7 100644 --- a/packages/shared/src/types/localization.ts +++ b/packages/shared/src/types/localization.ts @@ -1315,6 +1315,7 @@ type UnstableErrors = WithParamName<{ web3_missing_identifier: LocalizationValue; form_password_pwned: LocalizationValue; form_password_pwned__sign_in: LocalizationValue; + form_password_untrusted__sign_in: LocalizationValue; form_username_invalid_length: LocalizationValue<'min_length' | 'max_length'>; form_username_needs_non_number_char: LocalizationValue; form_username_invalid_character: LocalizationValue; From 72079b92251e22c021c31d42fd4c8570b26a6624 Mon Sep 17 00:00:00 2001 From: Vaggelis Yfantis Date: Mon, 1 Dec 2025 18:26:29 +0200 Subject: [PATCH 29/29] fix(clerk-js): Fix error message --- .../SignIn/__tests__/SignInFactorOne.test.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/clerk-js/src/ui/components/SignIn/__tests__/SignInFactorOne.test.tsx b/packages/clerk-js/src/ui/components/SignIn/__tests__/SignInFactorOne.test.tsx index 8987451ba97..c543db87364 100644 --- a/packages/clerk-js/src/ui/components/SignIn/__tests__/SignInFactorOne.test.tsx +++ b/packages/clerk-js/src/ui/components/SignIn/__tests__/SignInFactorOne.test.tsx @@ -369,9 +369,9 @@ describe('SignInFactorOne', () => { const errJSON = { code: 'form_password_untrusted', long_message: - "Your appears to have been compromised or it's no longer trusted and cannot be used. Please use another method to continue.", + "Your password appears to have been compromised or it's no longer trusted and cannot be used. Please use another method to continue.", message: - "Your appears to have been compromised or it's no longer trusted and cannot be used. Please use another method to continue.", + "Your password appears to have been compromised or it's no longer trusted and cannot be used. Please use another method to continue.", meta: { param_name: 'password' }, }; @@ -387,7 +387,7 @@ describe('SignInFactorOne', () => { await screen.findByText('Password compromised'); await screen.findByText( - "Your appears to have been compromised or it's no longer trusted and cannot be used. Please use another method to continue.", + "Your password appears to have been compromised or it's no longer trusted and cannot be used. Please use another method to continue.", ); await screen.findByText('Email code to hello@clerk.com'); @@ -410,9 +410,9 @@ describe('SignInFactorOne', () => { const errJSON = { code: 'form_password_untrusted', long_message: - "Your appears to have been compromised or it's no longer trusted and cannot be used. Please use another method to continue.", + "Your password appears to have been compromised or it's no longer trusted and cannot be used. Please use another method to continue.", message: - "Your appears to have been compromised or it's no longer trusted and cannot be used. Please use another method to continue.", + "Your password appears to have been compromised or it's no longer trusted and cannot be used. Please use another method to continue.", meta: { param_name: 'password' }, };