Skip to content

Commit 31c8836

Browse files
Release 5 -> master (#23)
* Refactor MFA factor type imports and usage for consistency * Adding support for MfaPhoneEnrollment screen * Added support for mfa-voice-enrollment screen * Added support for mfa-recovery-code-challenge * Added support for device-code-activation-* screen * Added support for device-code-activation screen * Added MFA voice challenge screen and integrated it into the app * Added support for password-reset-mfa-code-recovery-challenge screen * Updated password-reset-mfa-recovery-code-challenge screen * Added support for reset-password-mfa-voice-challenge screen * Added support for MFA Phone Challenge screen * Aded support for redeem-ticket screen * Added support for device-code-activation screen * update phone number property for MFA Phone Challenge screen * Added support mfa-recovery-code-challenge screen * Updated mfa-recovery-code-enrollment screen * Fixed the SDK version in package.json * Add Reset Password MFA Phone Challenge Screen * Added passkey-enrollment screen * refactor: update to showRememberDevice MFA email, OTP, push, SMS, and voice challenge screens * feat: add conditional rendering for voice and SMS options in MFA challenge screens * refactor: standardize string quotes to single quotes across MFA challenge screens * feat: add useEffect to initialize form values from untrustedData across MFA challenge screens * SDK-5931-fix(mfa-challenges): update rememberDevice handling for consistency across examples * update package version to ^0.1.0-beta.4 --------- Co-authored-by: Nandan Bhat <nandan.bhat@okta.com> Co-authored-by: nandan-bhat <167290944+nandan-bhat@users.noreply.github.com>
1 parent eb61973 commit 31c8836

File tree

25 files changed

+1714
-139
lines changed

25 files changed

+1714
-139
lines changed

package-lock.json

Lines changed: 44 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"preview": "vite preview"
1111
},
1212
"dependencies": {
13-
"@auth0/auth0-acul-js": "^0.1.0-beta.3",
13+
"@auth0/auth0-acul-js": "^0.1.0-beta.4",
1414
"react": "^18.3.1",
1515
"react-dom": "^18.3.1",
1616
"react-error-boundary": "^4.1.2"

src/App.tsx

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,21 @@ const OrganizationSelectionScreen = React.lazy(() => import("./screens/organizat
3535
const OrganizationPickerScreen = React.lazy(() => import("./screens/organization-picker"));
3636
const AcceptInvitationScreen = React.lazy(() => import("./screens/accept-invitation"));
3737
// const CustomizedConsentScreen = React.lazy(() => import("./screens/customized-consent"));
38+
const MfaPhoneEnrollmentScreen = React.lazy(() => import("./screens/mfa-phone-enrollment"));
39+
const MfaVoiceEnrollmentScreen = React.lazy(() => import("./screens/mfa-voice-enrollment"));
40+
const MfaRecoveryCodeChallengeScreen = React.lazy(() => import("./screens/mfa-recovery-code-challenge"));
41+
const DeviceCodeActivationAllowedScreen = React.lazy(() => import("./screens/device-code-activation-allowed"));
42+
const DeviceCodeActivationDeniedScreen = React.lazy(() => import("./screens/device-code-activation-denied"));
43+
const DeviceCodeActivationScreen = React.lazy(() => import("./screens/device-code-activation"));
44+
const MfaVoiceChallengeScreen = React.lazy(() => import("./screens/mfa-voice-challenge"))
45+
const ResetPasswordMfaRecoveryCodeChallengeScreen = React.lazy(() => import("./screens/reset-password-mfa-recovery-code-challenge"));
46+
const ResetPasswordMfaVoiceChallengeScreen = React.lazy(() => import("./screens/reset-password-mfa-voice-challenge"));
47+
const RedeemTicketScreen = React.lazy(() => import("./screens/redeem-ticket"));
48+
const DeviceCodeConfirmationScreen = React.lazy(() => import("./screens/device-code-confirmation"));
49+
const MfaPhoneChallengeScreen = React.lazy(() => import("./screens/mfa-phone-challenge"));
50+
const MfaRecoveryCodeEnrollmentScreen = React.lazy(() => import("./screens/mfa-recovery-code-enrollment"));
51+
const ResetPasswordMfaPhoneChallengeScreen = React.lazy(() => import("./screens/reset-password-mfa-phone-challenge"));
52+
const PasskeyEnrollmentScreen = React.lazy(() => import("./screens/passkey-enrollment"));
3853

3954

4055
const App: React.FC = () => {
@@ -114,6 +129,36 @@ const App: React.FC = () => {
114129
return <AcceptInvitationScreen />;
115130
// case "customized-consent":
116131
// return <CustomizedConsentScreen />;
132+
case "mfa-phone-enrollment":
133+
return <MfaPhoneEnrollmentScreen />;
134+
case "mfa-voice-enrollment":
135+
return <MfaVoiceEnrollmentScreen />;
136+
case "mfa-recovery-code-challenge":
137+
return <MfaRecoveryCodeChallengeScreen />;
138+
case "device-code-activation-allowed":
139+
return <DeviceCodeActivationAllowedScreen />;
140+
case "device-code-activation-denied":
141+
return <DeviceCodeActivationDeniedScreen />;
142+
case "device-code-activation":
143+
return <DeviceCodeActivationScreen />;
144+
case "mfa-voice-challenge":
145+
return <MfaVoiceChallengeScreen />;
146+
case "reset-password-mfa-recovery-code-challenge":
147+
return <ResetPasswordMfaRecoveryCodeChallengeScreen />;
148+
case "reset-password-mfa-voice-challenge":
149+
return <ResetPasswordMfaVoiceChallengeScreen />;
150+
case "redeem-ticket":
151+
return <RedeemTicketScreen />;
152+
case "device-code-confirmation":
153+
return <DeviceCodeConfirmationScreen />;
154+
case "mfa-phone-challenge":
155+
return <MfaPhoneChallengeScreen />;
156+
case "mfa-recovery-code-enrollment":
157+
return <MfaRecoveryCodeEnrollmentScreen />;
158+
case "reset-password-mfa-phone-challenge":
159+
return <ResetPasswordMfaPhoneChallengeScreen />;
160+
case "passkey-enrollment":
161+
return <PasskeyEnrollmentScreen />;
117162
default:
118163
return <>No screen rendered</>;
119164
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import React from 'react';
2+
import DeviceCodeActivationAllowed from '@auth0/auth0-acul-js/device-code-activation-allowed';
3+
4+
const DeviceCodeActivationAllowedScreen: React.FC = () => {
5+
const deviceCodeActivationAllowedManager = new DeviceCodeActivationAllowed();
6+
const { screen, transaction: { errors } } = deviceCodeActivationAllowedManager;
7+
const texts = screen.texts ?? {};
8+
9+
return (
10+
<div className="flex flex-col items-center min-h-screen bg-gray-100 p-4">
11+
<div className="bg-white shadow-md rounded px-8 pt-6 pb-8 w-full max-w-md text-center">
12+
<h2 className="text-2xl font-bold mb-4">
13+
{texts.eventTitle ?? 'Congratulations, you\'re all set!'}
14+
</h2>
15+
<p className="text-gray-700 mb-4">
16+
{texts.description ?? 'Your device is now connected.'}
17+
</p>
18+
19+
{errors?.length && (
20+
<div className="mt-2 space-y-1 text-left">
21+
{errors.map((error, idx) => (
22+
<p key={idx} className="text-red-600 text-sm">
23+
{error.message}
24+
</p>
25+
))}
26+
</div>
27+
)}
28+
</div>
29+
</div>
30+
);
31+
};
32+
33+
export default DeviceCodeActivationAllowedScreen;
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import React from 'react';
2+
import DeviceCodeActivationDenied from '@auth0/auth0-acul-js/device-code-activation-denied';
3+
4+
const DeviceCodeActivationDeniedScreen: React.FC = () => {
5+
const deviceCodeActivationDeniedManager = new DeviceCodeActivationDenied();
6+
const { screen, transaction: { errors } } = deviceCodeActivationDeniedManager;
7+
const texts = screen.texts ?? {};
8+
9+
return (
10+
<div className="flex flex-col items-center min-h-screen bg-gray-100 p-4">
11+
<div className="bg-white shadow-md rounded px-8 pt-6 pb-8 w-full max-w-md text-center">
12+
<h2 className="text-2xl font-bold mb-4">
13+
{texts.eventTitle ?? 'Device Code Activation Denied'}
14+
</h2>
15+
<p className="text-gray-700 mb-4">
16+
{texts.description ?? 'We are not able to activate your device.'}
17+
</p>
18+
19+
{errors?.length && (
20+
<div className="mt-2 space-y-1 text-left">
21+
{errors.map((error, idx) => (
22+
<p key={idx} className="text-red-600 text-sm">
23+
{error.message}
24+
</p>
25+
))}
26+
</div>
27+
)}
28+
</div>
29+
</div>
30+
);
31+
};
32+
33+
export default DeviceCodeActivationDeniedScreen;
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import React, { useState } from 'react';
2+
import DeviceCodeActivation from '@auth0/auth0-acul-js/device-code-activation';
3+
4+
const DeviceCodeActivationScreen: React.FC = () => {
5+
const [code, setCode] = useState('');
6+
const deviceCodeActivationManager = new DeviceCodeActivation();
7+
const { screen, transaction: { errors } } = deviceCodeActivationManager;
8+
const texts = screen.texts ?? {};
9+
10+
const handleContinue = () => {
11+
deviceCodeActivationManager.continue({ code });
12+
};
13+
14+
return (
15+
<div className="flex flex-col items-center min-h-screen bg-gray-100 p-4">
16+
<div className="bg-white shadow-md rounded px-8 pt-6 pb-8 w-full max-w-md">
17+
<h2 className="text-2xl font-bold mb-4 text-center">
18+
{texts.title ?? 'Device Activation'}
19+
</h2>
20+
<p className="text-sm text-gray-700 mb-4 text-center">
21+
{texts.description ?? 'Enter the code displayed on your device'}
22+
</p>
23+
24+
<input
25+
className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline mb-3"
26+
id="code"
27+
type="text"
28+
placeholder={texts.placeholder ?? 'Enter your one-time code'}
29+
value={code}
30+
onChange={(e) => setCode(e.target.value)}
31+
/>
32+
33+
{errors?.length && (
34+
<div className="mb-4 space-y-1">
35+
{errors.map((err, index) => (
36+
<p key={index} className="text-red-600 text-sm">
37+
{err.message}
38+
</p>
39+
))}
40+
</div>
41+
)}
42+
43+
<button
44+
className="w-full bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline"
45+
type="button"
46+
onClick={handleContinue}
47+
>
48+
{texts.buttonText ?? 'Continue'}
49+
</button>
50+
</div>
51+
</div>
52+
);
53+
};
54+
55+
export default DeviceCodeActivationScreen;
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import React from 'react';
2+
import DeviceCodeConfirmation from '@auth0/auth0-acul-js/device-code-confirmation';
3+
4+
const DeviceCodeConfirmationScreen: React.FC = () => {
5+
const deviceCodeConfirmationManager = new DeviceCodeConfirmation();
6+
const { screen, transaction: { errors } } = deviceCodeConfirmationManager;
7+
const texts = screen?.texts || {};
8+
9+
const handleConfirm = async () => {
10+
await deviceCodeConfirmationManager.confirm();
11+
};
12+
13+
const handleCancel = async () => {
14+
await deviceCodeConfirmationManager.cancel();
15+
};
16+
17+
return (
18+
<div className="flex flex-col items-center min-h-screen bg-gray-100 px-4">
19+
<div className="bg-white shadow-md rounded-xl p-6 w-full max-w-md space-y-4">
20+
<h1 className="text-2xl font-bold text-center">
21+
{texts.title ?? 'Device Confirmation'}
22+
</h1>
23+
24+
{texts.description && (
25+
<p className="text-sm text-gray-600 text-center">
26+
{texts.description}
27+
</p>
28+
)}
29+
30+
<div className="mt-4">
31+
<label className="block text-gray-700 text-sm font-medium mb-2">
32+
{texts.inputCodeLabel ?? 'Secure code'}
33+
</label>
34+
<input
35+
type="text"
36+
disabled
37+
value={screen?.data?.textCode ?? ''}
38+
className="w-full px-3 py-2 border border-gray-300 rounded-md bg-gray-100 text-gray-700 cursor-not-allowed"
39+
/>
40+
</div>
41+
42+
{texts.confirmationText && (
43+
<p className="text-xs text-gray-500 text-center mt-2">
44+
{texts.confirmationText}
45+
</p>
46+
)}
47+
48+
{errors?.length && (
49+
<div className="mt-2 space-y-1 text-left">
50+
{errors.map((error, idx) => (
51+
<p key={idx} className="text-red-600 text-sm">
52+
{error.message}
53+
</p>
54+
))}
55+
</div>
56+
)}
57+
58+
<div className="flex justify-between mt-6">
59+
<button
60+
className="bg-red-500 hover:bg-red-600 text-white font-semibold py-2 px-4 rounded-lg w-[45%]"
61+
onClick={handleCancel}
62+
>
63+
{texts.cancelButtonText ?? 'Cancel'}
64+
</button>
65+
<button
66+
className="bg-blue-600 hover:bg-blue-700 text-white font-semibold py-2 px-4 rounded-lg w-[45%]"
67+
onClick={handleConfirm}
68+
>
69+
{texts.confirmButtonText ?? 'Confirm'}
70+
</button>
71+
</div>
72+
</div>
73+
</div>
74+
);
75+
};
76+
77+
export default DeviceCodeConfirmationScreen;

src/screens/mfa-begin-enroll-options/index.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, { useCallback } from 'react';
2-
import MfaBeginEnrollOptions, { type FactorType } from '@auth0/auth0-acul-js/mfa-begin-enroll-options';
2+
import MfaBeginEnrollOptions, { type MfaEnrollFactorType } from '@auth0/auth0-acul-js/mfa-begin-enroll-options';
33

44
/** Enum for Factor Types */
55
enum FactorTypeEnum {
@@ -16,7 +16,7 @@ const MfaBeginEnrollOptionsScreen: React.FC = () => {
1616
const { tenant, screen: { texts } } = mfaBeginEnrollOptions;
1717

1818
/** Dynamically map factor IDs to display names */
19-
const factorDisplayNames: Record<FactorTypeEnum, string> = {
19+
const factorDisplayNames: Record<MfaEnrollFactorType, string> = {
2020
[FactorTypeEnum.PUSH_NOTIFICATION]: texts?.authenticatorNamesPushNotification ?? 'Push Notification (Auth0 Guardian)',
2121
[FactorTypeEnum.OTP]: texts?.authenticatorNamesOTP ?? 'One-Time Password (Google Authenticator)',
2222
[FactorTypeEnum.SMS]: texts?.authenticatorNamesSMS ?? 'SMS',
@@ -26,10 +26,10 @@ const MfaBeginEnrollOptionsScreen: React.FC = () => {
2626
};
2727

2828
/** Handles user selection of an MFA factor */
29-
const handleFactorSelection = useCallback(async (factor: FactorTypeEnum) => {
29+
const handleFactorSelection = useCallback(async (factor: MfaEnrollFactorType) => {
3030
try {
3131
await mfaBeginEnrollOptions.enroll({
32-
action: factor as FactorType
32+
action: factor as MfaEnrollFactorType
3333
});
3434
} catch (error) {
3535
console.error(`Error enrolling factor [${factor}]:`, error);
@@ -51,7 +51,7 @@ const MfaBeginEnrollOptionsScreen: React.FC = () => {
5151
<div className="bg-white py-8 px-4 shadow sm:rounded-lg sm:px-10">
5252
<div className="space-y-4">
5353
{tenant.enabledFactors?.map((factor) => {
54-
const factorEnum = factor as FactorTypeEnum;
54+
const factorEnum = factor as MfaEnrollFactorType;
5555
return (
5656
<button
5757
key={factor}

0 commit comments

Comments
 (0)