Created
June 7, 2023 20:11
-
-
Save perkinsjr/688a1b9a22c533173479c46579f0483c to your computer and use it in GitHub Desktop.
Shows multiple factor in custom flow
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { useState } from "react"; | |
import { useSignIn } from "@clerk/nextjs"; | |
import { useRouter } from "next/router"; | |
export default function SignInForm() { | |
const { isLoaded, signIn, setActive } = useSignIn(); | |
const [emailAddress, setEmailAddress] = useState(""); | |
const [password, setPassword] = useState(""); | |
const [totp, setTotp] = useState(""); | |
const [needsVerify, setNeedsVerify] = useState(false); | |
const [needsSMS, setNeedsSMS] = useState(false); | |
const [phoneCode, setPhoneCode] = useState(""); | |
const router = useRouter(); | |
// start the sign In process. | |
const handleSubmit = async (e) => { | |
e.preventDefault(); | |
if (!isLoaded) { | |
return; | |
} | |
try { | |
const result = await signIn.create({ | |
identifier: emailAddress, | |
password, | |
}); | |
// this assumes the user doesn't have a 2FA method enabled. So handle that how you want | |
if (result.status === "complete") { | |
console.log(result); | |
await setActive({ session: result.createdSessionId }); | |
router.push("/") | |
} | |
// Check if we need the second factor | |
if (result.status === "needs_second_factor") { | |
// Check if totp is enabled | |
const totpOn = signIn.supportedSecondFactors.find( | |
(f) => f.strategy === "totp", | |
); | |
if (totpOn) { | |
// show new UI | |
setNeedsVerify(true); | |
} else { | |
console.error("totp is not enabled for this user") | |
// go to phone and get phoneID | |
const phoneNumber = result.supportedSecondFactors.find( | |
(f) => f.strategy === "phone_code", | |
// This cast shouldn't be necessary but because TypeScript is dumb and can't infer it. | |
) as { phoneNumberId: string } | undefined; | |
// phone number found. | |
if (phoneNumber) { | |
setNeedsSMS(true); | |
// send text | |
result.prepareSecondFactor({ | |
strategy: "phone_code", | |
phoneNumberId: phoneNumber.phoneNumberId | |
}) | |
} | |
} | |
} | |
} catch (err: any) { | |
console.error("error", err.errors[0].longMessage) | |
} | |
}; | |
const totpInput = async (e) => { | |
e.preventDefault(); | |
const totpResult = await signIn?.attemptSecondFactor({ | |
strategy: "totp", | |
code: totp | |
}) | |
if (totpResult?.status === "complete") { | |
await setActive({ session: totpResult.createdSessionId }); | |
router.push("/") | |
} | |
} | |
const smsInput = async (e) => { | |
e.preventDefault(); | |
const totpResult = await signIn?.attemptSecondFactor({ | |
strategy: "phone_code", | |
code: phoneCode | |
}) | |
if (totpResult?.status === "complete") { | |
await setActive({ session: totpResult.createdSessionId }); | |
router.push("/") | |
} | |
} | |
return ( | |
<> | |
{!needsVerify && !needsSMS && ( | |
<div> | |
<form> | |
<div> | |
<label htmlFor="email">Email</label> | |
<input onChange={(e) => setEmailAddress(e.target.value)} id="email" name="email" type="email" /> | |
</div> | |
<div> | |
<label htmlFor="password">Password</label> | |
<input onChange={(e) => setPassword(e.target.value)} id="password" name="password" type="password" /> | |
</div> | |
<button onClick={handleSubmit}>Sign In</button> | |
</form> | |
</div> | |
)} | |
{needsVerify && ( | |
<div> | |
<form> | |
<div> | |
<label htmlFor="totp">ToTp</label> | |
<input onChange={(e) => setTotp(e.target.value)} id="totp" name="totp" type="text" /> | |
</div> | |
<button onClick={totpInput}>Verify MFA Code</button> | |
</form> | |
</div> | |
)} | |
{needsSMS && ( | |
<div> | |
<form> | |
<div> | |
<label htmlFor="phone">SMS CODE</label> | |
<input onChange={(e) => setPhoneCode(e.target.value)} id="phone" name="phone" type="text" /> | |
</div> | |
<button onClick={smsInput}>Verify SMS Code</button> | |
</form> | |
</div> | |
)} | |
</> | |
); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment