Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/pink-taxes-do.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@clerk/ui': patch
---

Remove back button on the sign-in password compromised/pwned error screen.

These errors are not recoverable by re-entering the password, so the back button led to a confusing dead end that would always take you back to the same error.
3 changes: 2 additions & 1 deletion packages/ui/src/components/SignIn/SignInFactorOne.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,8 @@ function SignInFactorOneInternal(): JSX.Element {
}

if (showAllStrategies || showForgotPasswordStrategies) {
const canGoBack = factorHasLocalStrategy(currentFactor);
// Password errors are not recoverable by re-entering the password, so we hide the back button
const canGoBack = factorHasLocalStrategy(currentFactor) && !passwordErrorCode;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

passwordErrorCode is to me not a very clear name for this flag (it sounds more general than it is) but I confirmed that it is just a union of 'compromised' | 'pwned' so it's exactly what we want to check.


const toggle = showAllStrategies ? toggleAllStrategies : toggleForgotPasswordStrategies;
const backHandler = () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -303,57 +303,6 @@ describe('SignInFactorOne', () => {
await screen.findByText('First, enter the code sent to your phone');
});

it('entering a pwned password, then going back and clicking forgot password should result in the correct title', async () => {
const { wrapper, fixtures } = await createFixtures(f => {
f.withEmailAddress();
f.withPassword();
f.withPreferredSignInStrategy({ strategy: 'password' });
f.startSignInWithEmailAddress({
supportPassword: true,
supportEmailCode: true,
supportResetPassword: true,
});
});
fixtures.signIn.prepareFirstFactor.mockReturnValueOnce(Promise.resolve({} as SignInResource));

const errJSON = {
code: 'form_password_pwned',
long_message:
'Password has been found in an online data breach. For account safety, please reset your password.',
message: 'Password has been found in an online data breach. For account safety, please reset your password.',
meta: { param_name: 'password' },
};

fixtures.signIn.attemptFirstFactor.mockRejectedValueOnce(
new ClerkAPIResponseError('Error', {
data: [errJSON],
status: 422,
}),
);

const { userEvent } = render(<SignInFactorOne />, { wrapper });
await userEvent.type(screen.getByLabelText('Password'), '123456');
await userEvent.click(screen.getByText('Continue'));

await screen.findByText('Password compromised');
await screen.findByText(
'This password has been found as part of a breach and can not be used, please reset your password.',
);
await screen.findByText('Or, sign in with another method');

// Go back
await userEvent.click(screen.getByText('Back'));

// Choose to reset password via "Forgot password" instead
await userEvent.click(screen.getByText(/Forgot password/i));
await screen.findByText('Forgot Password?');
expect(
screen.queryByText(
'This password has been found as part of a breach and can not be used, please reset your password.',
),
).not.toBeInTheDocument();
});

it('using an compromised password should show the compromised password screen', async () => {
const { wrapper, fixtures } = await createFixtures(f => {
f.withEmailAddress();
Expand Down
Loading