Skip to content

Commit de98ff4

Browse files
Add fixes for making sign in work properly for passkey
1 parent 70ab209 commit de98ff4

File tree

5 files changed

+64
-13
lines changed

5 files changed

+64
-13
lines changed

lib/ts/recipe/webauthn/components/themes/continueWithPasskey/index.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,18 @@ import type { ContinueFor, NormalisedConfig } from "../../../types";
2525
interface ContinueWithPasskeyProps {
2626
continueFor: ContinueFor;
2727
continueWithPasskeyClicked: (continueFor: ContinueFor) => void;
28+
isLoading?: boolean;
2829
}
2930

30-
const ContinueWithPasskey: React.FC<ContinueWithPasskeyProps> = ({ continueFor, continueWithPasskeyClicked }) => {
31+
const ContinueWithPasskey: React.FC<ContinueWithPasskeyProps> = ({
32+
continueFor,
33+
continueWithPasskeyClicked,
34+
isLoading = false,
35+
}) => {
3136
return (
3237
<div data-supertokens="continueWithPasskeyButtonWrapper">
3338
<Button
34-
isLoading={false}
39+
isLoading={isLoading}
3540
onClick={() => {
3641
continueWithPasskeyClicked(continueFor);
3742
}}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/* Copyright (c) 2024, VRAI Labs and/or its affiliates. All rights reserved.
2+
*
3+
* This software is licensed under the Apache License, Version 2.0 (the
4+
* "License") as published by the Apache Software Foundation.
5+
*
6+
* You may not use this file except in compliance with the License. You may
7+
* obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12+
* License for the specific language governing permissions and limitations
13+
* under the License.
14+
*/
15+
16+
import { withOverride } from "../../../../../components/componentOverride/withOverride";
17+
import { useTranslation } from "../../../../../translation/translationContext";
18+
19+
export const RecoverableError = withOverride(
20+
"PasskeyRecoverableError",
21+
(props: { errorMessageLabel: string }): JSX.Element => {
22+
const t = useTranslation();
23+
24+
return <div data-supertokens="passkeyRecoverableErrorContainer">{t(props.errorMessageLabel)}</div>;
25+
}
26+
);

lib/ts/recipe/webauthn/components/themes/signIn/index.tsx

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,16 @@ import { useUserContext } from "../../../../../usercontext";
2020
import UserContextWrapper from "../../../../../usercontext/userContextWrapper";
2121
import { handleFormSubmit } from "../../../../emailpassword/components/library/functions/form";
2222
import { ContinueWithPasskeyTheme } from "../continueWithPasskey";
23+
import { RecoverableError } from "../error/recoverableError";
2324
import { ThemeBase } from "../themeBase";
2425

2526
import type { APIFormField } from "../../../../../types";
2627
import type { SignInThemeProps } from "../../../types";
2728

2829
function PasskeySignInTheme(props: SignInThemeProps): JSX.Element {
2930
const userContext = useUserContext();
31+
const [error, setError] = React.useState<string | null>(null);
32+
const [isLoading, setIsLoading] = React.useState(false);
3033

3134
const callAPI = React.useCallback(
3235
async (_: APIFormField[], __: (id: string, value: string) => any) => {
@@ -41,6 +44,11 @@ function PasskeySignInTheme(props: SignInThemeProps): JSX.Element {
4144
userContext,
4245
});
4346

47+
if (response.status === "FAILED_TO_AUTHENTICATE_USER") {
48+
setError("Failed to authenticate user");
49+
return;
50+
}
51+
4452
return response;
4553
},
4654
[props, userContext]
@@ -50,10 +58,11 @@ function PasskeySignInTheme(props: SignInThemeProps): JSX.Element {
5058
const handleWebauthnSignInClick = async () => {
5159
await handleFormSubmit({
5260
callAPI: callAPI,
53-
clearError: () => alert("Clear error"),
54-
onError: () => alert("Error"),
55-
onFetchError: () => alert("Fetch error"),
61+
clearError: () => setError(null),
62+
onError: (error) => setError(error),
63+
onFetchError: () => setError("Failed to fetch from upstream"),
5664
onSuccess: (payload) => console.warn("payload: ", payload),
65+
setIsLoading: setIsLoading,
5766
});
5867
};
5968

@@ -64,12 +73,18 @@ function PasskeySignInTheme(props: SignInThemeProps): JSX.Element {
6473
return (
6574
<UserContextWrapper userContext={props.userContext}>
6675
<ThemeBase userStyles={[rootStyle, props.config.recipeRootStyle, activeStyle]}>
67-
<ContinueWithPasskeyTheme
68-
{...props}
69-
continueWithPasskeyClicked={handleWebauthnSignInClick}
70-
config={props.config}
71-
continueFor="SIGN_IN"
72-
/>
76+
<div data-supertokens="passkeySignInContainer">
77+
{error !== "" && error !== null && (
78+
<RecoverableError errorMessageLabel="WEBAUTHN_PASSKEY_RECOVERABLE_ERROR" />
79+
)}
80+
<ContinueWithPasskeyTheme
81+
{...props}
82+
continueWithPasskeyClicked={handleWebauthnSignInClick}
83+
config={props.config}
84+
continueFor="SIGN_IN"
85+
isLoading={isLoading}
86+
/>
87+
</div>
7388
</ThemeBase>
7489
</UserContextWrapper>
7590
);

lib/ts/recipe/webauthn/components/themes/signUp/confirmation.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import { withOverride } from "../../../../../components/componentOverride/withOverride";
1717
import { useTranslation } from "../../../../../translation/translationContext";
1818
import Button from "../../../../emailpassword/components/library/button";
19+
import { RecoverableError } from "../error/recoverableError";
1920

2021
import { ContinueWithoutPasskey } from "./continueWithoutPasskey";
2122
import { PasskeyFeatureBlocks } from "./featureBlocks";
@@ -42,7 +43,7 @@ export const PasskeyConfirmation = withOverride(
4243
</div>
4344
<PasskeyFeatureBlocks />
4445
{props.errorMessageLabel !== undefined && props.errorMessageLabel !== "" && (
45-
<div data-supertokens="passkeyRecoverableErrorContainer">{t(props.errorMessageLabel)}</div>
46+
<RecoverableError errorMessageLabel={props.errorMessageLabel} />
4647
)}
4748
<div data-supertokens="passkeyConfirmationFooter">
4849
<Button

lib/ts/recipe/webauthn/components/themes/styles.css

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@
102102
margin-top: 9px;
103103
}
104104

105-
[data-supertokens~="passkeyConfirmationContainer"] [data-supertokens~="passkeyRecoverableErrorContainer"] {
105+
[data-supertokens~="passkeyRecoverableErrorContainer"] {
106106
margin-top: 15px;
107107
border-radius: 6px;
108108
background-color: #fceaeb;
@@ -166,3 +166,7 @@
166166
text-decoration-skip-ink: none;
167167
color: #0076ff;
168168
}
169+
170+
[data-supertokens~="passkeySignInContainer"] {
171+
margin-bottom: 6px;
172+
}

0 commit comments

Comments
 (0)