Skip to content

Commit b27ca83

Browse files
authored
feat(clerk-js,shared,types,localizations): New client_mismatch status for email link sign in/up (#3367)
* feat(clerk-js,shared,types,localizations): New client_mismatch status for email link sign in/up * feat(localizations): Update email link client_mistmatch messages
1 parent 34befee commit b27ca83

File tree

10 files changed

+53
-1
lines changed

10 files changed

+53
-1
lines changed

.changeset/chilled-laws-pump.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@clerk/localizations': minor
3+
---
4+
5+
Added new keys for email link verification under `signIn.emailLink.clientMismatch` and `signUp.emailLink.clientMismatch`

.changeset/tricky-tomatoes-repair.md

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'@clerk/clerk-js': minor
3+
'@clerk/shared': minor
4+
'@clerk/types': minor
5+
---
6+
7+
Introduce new `client_mismatch` verification status for email link sign-in and sign-up. This error (and its message) will be shown if a verification link was opened in another device/browser from which the user initiated the sign-in/sign-up attempt. This functionality needs to be enabled in the Clerk dashboard.

packages/clerk-js/src/core/clerk.ts

+2
Original file line numberDiff line numberDiff line change
@@ -981,6 +981,8 @@ export class Clerk implements ClerkInterface {
981981
const verificationStatus = getClerkQueryParam('__clerk_status');
982982
if (verificationStatus === 'expired') {
983983
throw new EmailLinkError(EmailLinkErrorCode.Expired);
984+
} else if (verificationStatus === 'client_mismatch') {
985+
throw new EmailLinkError(EmailLinkErrorCode.ClientMismatch);
984986
} else if (verificationStatus !== 'verified') {
985987
throw new EmailLinkError(EmailLinkErrorCode.Failed);
986988
}

packages/clerk-js/src/ui/common/EmailLinkCompleteFlowCard.tsx

+8
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ const signInLocalizationKeys = {
2424
title: localizationKeys('signIn.emailLink.expired.title'),
2525
subtitle: localizationKeys('signIn.emailLink.expired.subtitle'),
2626
},
27+
client_mismatch: {
28+
title: localizationKeys('signIn.emailLink.clientMismatch.title'),
29+
subtitle: localizationKeys('signIn.emailLink.clientMismatch.subtitle'),
30+
},
2731
};
2832

2933
const signUpLocalizationKeys = {
@@ -40,6 +44,10 @@ const signUpLocalizationKeys = {
4044
...signInLocalizationKeys.loading,
4145
title: localizationKeys('signUp.emailLink.loading.title'),
4246
},
47+
client_mismatch: {
48+
...signInLocalizationKeys.client_mismatch,
49+
subtitle: localizationKeys('signUp.emailLink.clientMismatch.subtitle'),
50+
},
4351
};
4452

4553
export const SignInEmailLinkFlowComplete = withCardStateProvider((props: Omit<EmailLinkVerifyProps, 'texts'>) => {

packages/clerk-js/src/ui/common/EmailLinkStatusCard.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ const StatusToIcon: Record<Exclude<VerificationStatus, 'loading'>, React.Compone
2020
verified_switch_tab: SwitchArrows,
2121
expired: ExclamationTriangle,
2222
failed: ExclamationTriangle,
23+
client_mismatch: ExclamationTriangle,
2324
};
2425

2526
const statusToColor = (theme: InternalTheme, status: Exclude<VerificationStatus, 'loading'>) =>
@@ -28,6 +29,7 @@ const statusToColor = (theme: InternalTheme, status: Exclude<VerificationStatus,
2829
verified_switch_tab: theme.colors.$primary500,
2930
expired: theme.colors.$warning500,
3031
failed: theme.colors.$danger500,
32+
client_mismatch: theme.colors.$warning500,
3133
}[status]);
3234

3335
export const EmailLinkStatusCard = (props: EmailLinkStatusCardProps) => {

packages/clerk-js/src/ui/common/EmailLinkVerify.tsx

+3
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ export const EmailLinkVerify = (props: EmailLinkVerifyProps) => {
4343
if (isEmailLinkError(err) && err.code === EmailLinkErrorCode.Expired) {
4444
status = 'expired';
4545
}
46+
if (isEmailLinkError(err) && err.code === EmailLinkErrorCode.ClientMismatch) {
47+
status = 'client_mismatch';
48+
}
4649
setVerificationStatus(status);
4750
}
4851
};

packages/clerk-js/src/utils/getClerkQueryParam.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,13 @@ type ClerkQueryParamsToValuesMap = {
2626
__clerk_help: string;
2727
};
2828

29-
export type VerificationStatus = 'expired' | 'failed' | 'loading' | 'verified' | 'verified_switch_tab';
29+
export type VerificationStatus =
30+
| 'expired'
31+
| 'failed'
32+
| 'loading'
33+
| 'verified'
34+
| 'verified_switch_tab'
35+
| 'client_mismatch';
3036

3137
export function getClerkQueryParam<T extends ClerkQueryParam>(param: T): ClerkQueryParamsToValuesMap[T] | null {
3238
const val = new URL(window.location.href).searchParams.get(param);

packages/localizations/src/en-US.ts

+10
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,11 @@ export const enUS: LocalizationResource = {
325325
subtitleNewTab: 'Return to the newly opened tab to continue',
326326
titleNewTab: 'Signed in on other tab',
327327
},
328+
clientMismatch: {
329+
subtitle:
330+
'To continue, open the verification link on the device and browser from which you initiated the sign-in',
331+
title: 'Verification link is invalid for this device',
332+
},
328333
},
329334
forgotPassword: {
330335
formTitle: 'Reset password code',
@@ -426,6 +431,11 @@ export const enUS: LocalizationResource = {
426431
subtitleNewTab: 'Return to previous tab to continue',
427432
title: 'Successfully verified email',
428433
},
434+
clientMismatch: {
435+
subtitle:
436+
'To continue, open the verification link on the device and browser from which you initiated the sign-up',
437+
title: 'Verification link is invalid for this device',
438+
},
429439
},
430440
phoneCode: {
431441
formSubtitle: 'Enter the verification code sent to your phone number',

packages/shared/src/error.ts

+1
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ export function isEmailLinkError(err: Error): err is EmailLinkError {
188188
export const EmailLinkErrorCode = {
189189
Expired: 'expired',
190190
Failed: 'failed',
191+
ClientMismatch: 'client_mismatch',
191192
};
192193

193194
const DefaultMessages = Object.freeze({

packages/types/src/localization.ts

+8
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,10 @@ type _LocalizationResource = {
117117
subtitle: LocalizationValue;
118118
subtitleNewTab: LocalizationValue;
119119
};
120+
clientMismatch: {
121+
title: LocalizationValue;
122+
subtitle: LocalizationValue;
123+
};
120124
};
121125
emailCode: {
122126
title: LocalizationValue;
@@ -221,6 +225,10 @@ type _LocalizationResource = {
221225
title: LocalizationValue;
222226
subtitle: LocalizationValue;
223227
};
228+
clientMismatch: {
229+
title: LocalizationValue;
230+
subtitle: LocalizationValue;
231+
};
224232
};
225233
phoneCode: {
226234
title: LocalizationValue;

0 commit comments

Comments
 (0)