Skip to content
Merged
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
5 changes: 5 additions & 0 deletions .changeset/tidy-device-trust-methods.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@clerk/ui': patch
---

Hide the “Use another method” action during Device Trust and second-factor verification when no alternative verification method is available.
1 change: 1 addition & 0 deletions integration/tests/client-trust.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withNeedsClientTrust] })(

// Should contain the new device verification notice
await expect(u.page.getByText("You're signing in from a new device.")).toBeVisible();
await expect(u.page.getByRole('link', { name: 'Use another method' })).toBeHidden();

// User should not be signed in yet since client trust step is required
await u.po.expect.toBeSignedOut();
Expand Down
8 changes: 5 additions & 3 deletions packages/ui/src/components/SignIn/SignInClientTrust.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ function SignInClientTrustInternal(): JSX.Element {
showAllStrategies,
toggleAllStrategies,
} = useSecondFactorSelection(signIn.supportedSecondFactors);
const onShowAlternativeMethodsClicked =
signIn.supportedSecondFactors && signIn.supportedSecondFactors.length > 1 ? toggleAllStrategies : undefined;

if (!currentFactor) {
return <LoadingCard />;
Expand All @@ -41,7 +43,7 @@ function SignInClientTrustInternal(): JSX.Element {
factorAlreadyPrepared={factorAlreadyPrepared}
onFactorPrepare={handleFactorPrepare}
factor={currentFactor}
onShowAlternativeMethodsClicked={toggleAllStrategies}
onShowAlternativeMethodsClicked={onShowAlternativeMethodsClicked}
/>
);
case 'email_code':
Expand All @@ -51,7 +53,7 @@ function SignInClientTrustInternal(): JSX.Element {
factorAlreadyPrepared={factorAlreadyPrepared}
onFactorPrepare={handleFactorPrepare}
factor={currentFactor}
onShowAlternativeMethodsClicked={toggleAllStrategies}
onShowAlternativeMethodsClicked={onShowAlternativeMethodsClicked}
/>
);
case 'email_link':
Expand All @@ -61,7 +63,7 @@ function SignInClientTrustInternal(): JSX.Element {
factorAlreadyPrepared={factorAlreadyPrepared}
onFactorPrepare={handleFactorPrepare}
factor={currentFactor}
onShowAlternativeMethodsClicked={toggleAllStrategies}
onShowAlternativeMethodsClicked={onShowAlternativeMethodsClicked}
/>
);
default:
Expand Down
12 changes: 7 additions & 5 deletions packages/ui/src/components/SignIn/SignInFactorTwo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ function SignInFactorTwoInternal(): JSX.Element {
showAllStrategies,
toggleAllStrategies,
} = useSecondFactorSelection(signIn.supportedSecondFactors);
const onShowAlternativeMethodsClicked =
signIn.supportedSecondFactors && signIn.supportedSecondFactors.length > 1 ? toggleAllStrategies : undefined;

React.useEffect(() => {
if (clerk.__internal_setActiveInProgress) {
Expand Down Expand Up @@ -69,7 +71,7 @@ function SignInFactorTwoInternal(): JSX.Element {
factorAlreadyPrepared={factorAlreadyPrepared}
onFactorPrepare={handleFactorPrepare}
factor={currentFactor}
onShowAlternativeMethodsClicked={toggleAllStrategies}
onShowAlternativeMethodsClicked={onShowAlternativeMethodsClicked}
/>
);
case 'totp':
Expand All @@ -78,18 +80,18 @@ function SignInFactorTwoInternal(): JSX.Element {
factorAlreadyPrepared={factorAlreadyPrepared}
onFactorPrepare={handleFactorPrepare}
factor={currentFactor}
onShowAlternativeMethodsClicked={toggleAllStrategies}
onShowAlternativeMethodsClicked={onShowAlternativeMethodsClicked}
/>
);
case 'backup_code':
return <SignInFactorTwoBackupCodeCard onShowAlternativeMethodsClicked={toggleAllStrategies} />;
return <SignInFactorTwoBackupCodeCard onShowAlternativeMethodsClicked={onShowAlternativeMethodsClicked} />;
case 'email_code':
return (
<SignInFactorTwoEmailCodeCard
factorAlreadyPrepared={factorAlreadyPrepared}
onFactorPrepare={handleFactorPrepare}
factor={currentFactor}
onShowAlternativeMethodsClicked={toggleAllStrategies}
onShowAlternativeMethodsClicked={onShowAlternativeMethodsClicked}
/>
);
case 'email_link':
Expand All @@ -98,7 +100,7 @@ function SignInFactorTwoInternal(): JSX.Element {
factorAlreadyPrepared={factorAlreadyPrepared}
onFactorPrepare={handleFactorPrepare}
factor={currentFactor}
onShowAlternativeMethodsClicked={toggleAllStrategies}
onShowAlternativeMethodsClicked={onShowAlternativeMethodsClicked}
/>
);
default:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { navigateOnSignInProtectGate } from './handleProtectCheck';
import { isResetPasswordStrategy } from './utils';

type SignInFactorTwoBackupCodeCardProps = {
onShowAlternativeMethodsClicked: React.MouseEventHandler;
onShowAlternativeMethodsClicked?: React.MouseEventHandler;
};

export const SignInFactorTwoBackupCodeCard = (props: SignInFactorTwoBackupCodeCardProps) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import type { SignInResource } from '@clerk/shared/types';
import { describe, expect, it } from 'vitest';

import { bindCreateFixtures } from '@/test/create-fixtures';
import { render, screen } from '@/test/utils';

import { SignInClientTrust } from '../SignInClientTrust';

const { createFixtures } = bindCreateFixtures('SignIn');

describe('SignInClientTrust', () => {
describe('Use another method', () => {
it('does not render when only one verification factor is available', async () => {
const { wrapper, fixtures } = await createFixtures(f => {
f.startSignInClientTrust({ supportPhoneCode: true });
});

fixtures.signIn.prepareSecondFactor.mockResolvedValueOnce({} as SignInResource);
render(<SignInClientTrust />, { wrapper });

expect(screen.queryByText('Use another method')).not.toBeInTheDocument();
});

it('renders when multiple verification factors are available', async () => {
const { wrapper, fixtures } = await createFixtures(f => {
f.startSignInClientTrust({ supportPhoneCode: true, supportEmailCode: true });
});

fixtures.signIn.prepareSecondFactor.mockResolvedValueOnce({} as SignInResource);
render(<SignInClientTrust />, { wrapper });

expect(screen.getByText('Use another method')).toBeInTheDocument();
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,28 @@ describe('SignInFactorTwo', () => {
});

describe('Use another method', () => {
it('does not render when only one verification factor is available', async () => {
const { wrapper, fixtures } = await createFixtures(f => {
f.startSignInFactorTwo({ supportPhoneCode: true });
});

fixtures.signIn.prepareSecondFactor.mockResolvedValueOnce({} as SignInResource);
render(<SignInFactorTwo />, { wrapper });

expect(screen.queryByText('Use another method')).not.toBeInTheDocument();
});

it('renders when multiple verification factors are available', async () => {
const { wrapper, fixtures } = await createFixtures(f => {
f.startSignInFactorTwo({ supportPhoneCode: true, supportEmailCode: true });
});

fixtures.signIn.prepareSecondFactor.mockResolvedValueOnce({} as SignInResource);
render(<SignInFactorTwo />, { wrapper });

expect(screen.getByText('Use another method')).toBeInTheDocument();
});

it('renders the other authentication methods list component when clicking on "Use another method"', async () => {
const { wrapper, fixtures } = await createFixtures(f => {
f.withEmailAddress();
Expand Down
24 changes: 21 additions & 3 deletions packages/ui/src/test/fixture-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ const createSignInFixtureHelpers = (baseClient: ClientJSON) => {
type SignInFactorTwoParams = {
identifier?: string;
supportPhoneCode?: boolean;
supportEmailCode?: boolean;
supportTotp?: boolean;
supportBackupCode?: boolean;
supportResetPasswordEmail?: boolean;
Expand Down Expand Up @@ -185,17 +186,21 @@ const createSignInFixtureHelpers = (baseClient: ClientJSON) => {
} as SignInJSON;
};

const startSignInFactorTwo = (params?: SignInFactorTwoParams) => {
const startSignInVerification = (
status: Extract<SignInJSON['status'], 'needs_client_trust' | 'needs_second_factor'>,
params?: SignInFactorTwoParams,
) => {
const {
identifier = '+30 691 1111111',
supportPhoneCode = true,
supportEmailCode,
supportTotp,
supportBackupCode,
supportResetPasswordEmail,
supportResetPasswordPhone,
} = params || {};
baseClient.sign_in = {
status: 'needs_second_factor',
status,
identifier,
...(supportResetPasswordEmail
? {
Expand All @@ -216,13 +221,20 @@ const createSignInFixtureHelpers = (baseClient: ClientJSON) => {
supported_identifiers: ['email_address', 'phone_number'],
supported_second_factors: [
...(supportPhoneCode ? [{ strategy: 'phone_code', safe_identifier: identifier || 'n*****@clerk.com' }] : []),
...(supportEmailCode ? [{ strategy: 'email_code', safe_identifier: 'n*****@clerk.com' }] : []),
Comment thread
tmilewski marked this conversation as resolved.
...(supportTotp ? [{ strategy: 'totp', safe_identifier: identifier || 'n*****@clerk.com' }] : []),
...(supportBackupCode ? [{ strategy: 'backup_code', safe_identifier: identifier || 'n*****@clerk.com' }] : []),
],
user_data: { ...(createUserFixture() as any) },
} as SignInJSON;
};

const startSignInFactorTwo = (params?: SignInFactorTwoParams) =>
startSignInVerification('needs_second_factor', params);

const startSignInClientTrust = (params?: SignInFactorTwoParams) =>
startSignInVerification('needs_client_trust', params);

const startSignInWithProtectCheck = (params?: {
expiresAt?: number;
uiHints?: Record<string, string>;
Expand All @@ -249,7 +261,13 @@ const createSignInFixtureHelpers = (baseClient: ClientJSON) => {
} as SignInJSON;
};

return { startSignInWithEmailAddress, startSignInWithPhoneNumber, startSignInFactorTwo, startSignInWithProtectCheck };
return {
startSignInWithEmailAddress,
startSignInWithPhoneNumber,
startSignInFactorTwo,
startSignInClientTrust,
startSignInWithProtectCheck,
};
};

const createSignUpFixtureHelpers = (baseClient: ClientJSON) => {
Expand Down
Loading