Custom email/password flow
Clerk supports password authentication, which allows users to sign up and sign in using their email address and password. This guide will walk you through how to build a custom email/password sign-up and sign-in flow using the useSignUp()
and useSignIn()
React hooks.
Enable password and email
In the Clerk dashboard, you will need to enable both email and password as a sign-in and sign-up method. Go to User & Authentication > Email, Phone, and Username(opens in a new tab).Toggle on Email address and Password.
Create sign up flow
The email/password sign-up flow requires users to provide their email address and their password and returns a newly-created user with an active session.
A successful sign-up consists of the following steps:
- Initiate the sign-up process by collecting the user's email address and password.
- Prepare the email address verification, which sends a one-time code to the given address.
- Attempt to complete the email address verification by supplying the one-time code.
- If the email address verification is successful, complete the sign-up process by creating the user account and setting their session as active.
'use client' import * as React from 'react'; import { useSignUp } from '@clerk/nextjs'; import { useRouter } from 'next/navigation'; import { ClerkAPIErrorJSON } from '@clerk/types'; export default function Page() { const { isLoaded, signUp, setActive } = useSignUp(); const [emailAddress, setEmailAddress] = React.useState(""); const [password, setPassword] = React.useState(""); const [verifying, setVerifying] = React.useState(false); const [code, setCode] = React.useState(""); const router = useRouter(); // This function will handle the user submitting their email and password const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!isLoaded) return; // Start the sign-up process using the email and password provided try { await signUp.create({ emailAddress, password }); // Send the user an email with the verification code await signUp.prepareEmailAddressVerification({ strategy: 'email_code' }); // Set 'verifying' true to display second form and capture the OTP code setVerifying(true); } catch (err: any) { // This can return an array of errors. // See https://clerk.com/docs/custom-flows/error-handling to learn about error handling console.error('Error:', JSON.stringify(err, null, 2)); } } // This function will handle the user submitting a code for verification const handleVerify = async (e: React.FormEvent) => { e.preventDefault(); if (!isLoaded) return; try { // Submit the code that the user provides to attempt verification const completeSignUp = await signUp.attemptEmailAddressVerification({ code }); if (completeSignUp.status !== "complete") { // The status can also be `abandoned` or `missing_requirements` // Please see https://clerk.com/docs/references/react/use-sign-up#result-status for more information console.log(JSON.stringify(completeSignUp, null, 2)); } // Check the status to see if it is complete // If complete, the user has been created -- set the session active if (completeSignUp.status === "complete") { await setActive({ session: completeSignUp.createdSessionId }); // Redirect the user to a post sign-up route router.push("/"); } } catch (err: any) { // This can return an array of errors. // See https://clerk.com/docs/custom-flows/error-handling to learn about error handling console.error('Error:', JSON.stringify(err, null, 2)); } } // Once the sign-up form was submitted, verifying was set to true and as a result, this verification form is presented to the user to input their verification code. if (verifying) { return ( <form onSubmit={handleVerify}> <label id="code">Code</label> <input value={code} id="code" name="code" onChange={(e) => setCode(e.target.value)} /> <button type="submit">Complete Sign Up</button> </form> ) } // Display the initial sign-up form to capture the email and password return ( <form onSubmit={handleSubmit}> <div> <label htmlFor="email">Email address</label> <input id="email" type='email' name="email" value={emailAddress} onChange={(e) => setEmailAddress(e.target.value)} /> </div> <div> <label className="block text-sm mt-8" htmlFor="password">Password</label> <input id="password" type='password' name="password" value={password} onChange={(e) => setPassword(e.target.value)} /> </div> <div> <button type="submit">Verify Email</button> </div> </form> ); }
pages/sign-up/[[...index]].tsximport { useState } from "react"; import { useSignUp } from "@clerk/nextjs"; import { useRouter } from "next/router"; export default function SignUpForm() { const { isLoaded, signUp, setActive } = useSignUp(); const [emailAddress, setEmailAddress] = useState(""); const [password, setPassword] = useState(""); const [pendingVerification, setPendingVerification] = useState(false); const [code, setCode] = useState(""); const router = useRouter(); // This function will handle the user submitting their email and password const handleSubmit = async (e) => { e.preventDefault(); if (!isLoaded) { return; } // Start the sign-up process using the email and password provided try { await signUp.create({ emailAddress, password, }); // Send the user an email with the verification code await signUp.prepareEmailAddressVerification({ strategy: "email_code" }); // Set 'verifying' true to display second form and capture the OTP code setPendingVerification(true); } catch (err: any) { // This can return an array of errors. // See https://clerk.com/docs/custom-flows/error-handling to learn about error handling console.error(JSON.stringify(err, null, 2)); } }; // This function will handle the user submitting a code for verification const onPressVerify = async (e) => { e.preventDefault(); if (!isLoaded) { return; } try { // Submit the code that the user provides to attempt verification const completeSignUp = await signUp.attemptEmailAddressVerification({ code, }); if (completeSignUp.status !== "complete") { // The status can also be `abandoned` or `missing_requirements` // Please see https://clerk.com/docs/references/react/use-sign-up#result-status for more information console.log(JSON.stringify(completeSignUp, null, 2)); } // Check the status to see if it is complete // If complete, the user has been created -- set the session active if (completeSignUp.status === "complete") { await setActive({ session: completeSignUp.createdSessionId }) // Redirect the user to a post sign-up route router.push("/"); } } catch (err: any) { // This can return an array of errors. // See https://clerk.com/docs/custom-flows/error-handling to learn about error handling console.error(JSON.stringify(err, null, 2)); } }; return ( <div> {!pendingVerification && ( <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 up</button> </form> )} {pendingVerification && ( <div> <form> <input value={code} placeholder="Code..." onChange={(e) => setCode(e.target.value)} /> <button onClick={onPressVerify}> Verify Email </button> </form> </div> )} </div> ); }
signup.tsximport { useState } from "react"; import { useSignUp } from "@clerk/clerk-react"; export default function SignUpForm() { const { isLoaded, signUp, setActive } = useSignUp(); const [emailAddress, setEmailAddress] = useState(""); const [password, setPassword] = useState(""); const [verifying, setVerifying] = React.useState(false); const [code, setCode] = useState(""); // This function will handle the user submitting their email and password const handleSubmit = async (e) => { e.preventDefault(); if (!isLoaded) { return; } // Start the sign-up process using the email and password provided try { await signUp.create({ emailAddress, password, }); // Send the user an email with the verification code await signUp.prepareEmailAddressVerification({ strategy: "email_code" }); // Set 'verifying' true to display second form and capture the OTP code setVerifying(true); } catch (err: any) { // This can return an array of errors. // See https://clerk.com/docs/custom-flows/error-handling to learn about error handling console.error(JSON.stringify(err, null, 2)); } }; // This function will handle the user submitting a code for verification const handleVerify = async (e) => { e.preventDefault(); if (!isLoaded) { return; } try { // Submit the code that the user provides to attempt verification const completeSignUp = await signUp.attemptEmailAddressVerification({ code, }); if (completeSignUp.status !== "complete") { // The status can also be `abandoned` or `missing_requirements` // Please see https://clerk.com/docs/references/react/use-sign-up#result-status for more information console.log(JSON.stringify(completeSignUp, null, 2)); } // Check the status to see if it is complete // If complete, the user has been created -- set the session active if (completeSignUp.status === "complete") { await setActive({ session: completeSignUp.createdSessionId }) // Handle your own logic here, like redirecting to a new page if needed. } } catch (err: any) { // This can return an array of errors. // See https://clerk.com/docs/custom-flows/error-handling to learn about error handling console.error(JSON.stringify(err, null, 2)); } }; return ( <div> {!verifying && ( <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 up</button> </form> )} {verifying && ( <div> <form> <input value={code} placeholder="Code..." onChange={(e) => setCode(e.target.value)} /> <button onClick={handleVerify}> Verify Email </button> </form> </div> )} </div> ); }
app/routes/sign-up/$.tsximport { useState } from "react"; import { useSignUp } from "@clerk/remix"; export default function SignUpForm() { const { isLoaded, signUp, setActive } = useSignUp(); const [emailAddress, setEmailAddress] = useState(""); const [password, setPassword] = useState(""); const [verifying, setVerifying] = React.useState(false); const [code, setCode] = useState(""); // This function will handle the user submitting their email and password const handleSubmit = async (e) => { e.preventDefault(); if (!isLoaded) { return; } // Start the sign-up process using the email and password provided try { await signUp.create({ emailAddress, password, }); // Send the user an email with the verification code await signUp.prepareEmailAddressVerification({ strategy: "email_code" }); // Set 'verifying' true to display second form and capture the OTP code setVerifying(true); } catch (err: any) { // This can return an array of errors. // See https://clerk.com/docs/custom-flows/error-handling to learn about error handling console.error(JSON.stringify(err, null, 2)); } }; // This function will handle the user submitting a code for verification const handleVerify = async (e) => { e.preventDefault(); if (!isLoaded) { return; } try { // Submit the code that the user provides to attempt verification const completeSignUp = await signUp.attemptEmailAddressVerification({ code, }); if (completeSignUp.status !== "complete") { // The status can also be `abandoned` or `missing_requirements` // Please see https://clerk.com/docs/references/react/use-sign-up#result-status for more information or if the user needs to complete more steps.*/ console.log(JSON.stringify(completeSignUp, null, 2)); } // Check the status to see if it is complete // If complete, the user has been created -- set the session active if (completeSignUp.status === "complete") { await setActive({ session: completeSignUp.createdSessionId }) // Handle your own logic here, like redirecting to a new page if needed. } } catch (err: any) { // This can return an array of errors. // See https://clerk.com/docs/custom-flows/error-handling to learn about error handling console.error(JSON.stringify(err, null, 2)); } }; return ( <div> {!verifying && ( <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 up</button> </form> )} {verifying && ( <div> <form> <input value={code} placeholder="Code..." onChange={(e) => setCode(e.target.value)} /> <button onClick={handleVerify}> Verify Email </button> </form> </div> )} </div> ); }
sign-up.tsximport { useState } from "react"; // Use the react package when using Gatsby import { useSignUp } from "@clerk/react"; import { useRouter } from "next/router"; export default function SignUpForm() { const { isLoaded, signUp, setActive } = useSignUp(); const [emailAddress, setEmailAddress] = useState(""); const [password, setPassword] = useState(""); const [verifying, setVerifying] = React.useState(false); const [code, setCode] = useState(""); const router = useRouter(); // This function will handle the user submitting their email and password const handleSubmit = async (e) => { e.preventDefault(); if (!isLoaded) { return; } // Start the sign-up process using the email and password provided try { await signUp.create({ emailAddress, password, }); // Send the user an email with the verification code await signUp.prepareEmailAddressVerification({ strategy: "email_code" }); // Set 'verifying' true to display second form and capture the OTP code setVerifying(true); } catch (err: any) { // This can return an array of errors. // See https://clerk.com/docs/custom-flows/error-handling to learn about error handling console.error(JSON.stringify(err, null, 2)); } }; // This function will handle the user submitting a code for verification const handleVerify = async (e) => { e.preventDefault(); if (!isLoaded) { return; } try { // Submit the code that the user provides to attempt verification const completeSignUp = await signUp.attemptEmailAddressVerification({ code, }); if (completeSignUp.status !== "complete") { // The status can also be `abandoned` or `missing_requirements` // Please see https://clerk.com/docs/references/react/use-sign-up#result-status for more information console.log(JSON.stringify(completeSignUp, null, 2)); } // Check the status to see if it is complete // If complete, the user has been created -- set the session active if (completeSignUp.status === "complete") { await setActive({ session: completeSignUp.createdSessionId }) // Redirect the user to a post sign-up route router.push("/"); } } catch (err: any) { // This can return an array of errors. // See https://clerk.com/docs/custom-flows/error-handling to learn about error handling console.error(JSON.stringify(err, null, 2)); } }; return ( <div> {!verifying && ( <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 up</button> </form> )} {verifying && ( <div> <form> <input value={code} placeholder="Code..." onChange={(e) => setCode(e.target.value)} /> <button onClick={handleVerify}> Verify Email </button> </form> </div> )} </div> ); }
SignUpScreen.tsximport * as React from "react"; import { Text, TextInput, TouchableOpacity, View } from "react-native"; import { useSignUp } from "@clerk/clerk-expo"; export default function SignUpScreen() { const { isLoaded, signUp, setActive } = useSignUp(); const [emailAddress, setEmailAddress] = React.useState(""); const [password, setPassword] = React.useState(""); const [verifying, setVerifying] = React.useState(false); const [code, setCode] = React.useState(""); // This function will handle the user submitting their email and password const onSignUpPress = async () => { if (!isLoaded) { return; } // Start the sign-up process using the email and password provided try { await signUp.create({ emailAddress, password, }); // Send the user an email with the verification code await signUp.prepareEmailAddressVerification({ strategy: "email_code" }); // Set 'verifying' true to display second form and capture the OTP code setVerifying(true); } catch (err: any) { // This can return an array of errors. // See https://clerk.com/docs/custom-flows/error-handling to learn about error handling console.error(JSON.stringify(err, null, 2)); } }; // This function will handle the user submitting a code for verification const handleVerify = async () => { if (!isLoaded) { return; } try { // Submit the code that the user provides to attempt verification const completeSignUp = await signUp.attemptEmailAddressVerification({ code, }); if (completeSignUp.status !== "complete") { // The status can also be `abandoned` or `missing_requirements` // Please see https://clerk.com/docs/references/react/use-sign-up#result-status for more information console.log(JSON.stringify(completeSignUp, null, 2)); } // Check the status to see if it is complete // If complete, the user has been created -- set the session active if (completeSignUp.status === "complete") { await setActive({ session: completeSignUp.createdSessionId }); // Handle your own logic here, like redirecting to a new page if needed. } } catch (err: any) { // This can return an array of errors. // See https://clerk.com/docs/custom-flows/error-handling to learn about error handling console.error(JSON.stringify(err, null, 2)); } }; return ( <View> {!verifying && ( <View> <View> <TextInput autoCapitalize="none" value={emailAddress} placeholder="Email..." onChangeText={(email) => setEmailAddress(email)} /> </View> <View> <TextInput value={password} placeholder="Password..." placeholderTextColor="#000" secureTextEntry={true} onChangeText={(password) => setPassword(password)} /> </View> <TouchableOpacity onPress={onSignUpPress}> <Text>Sign up</Text> </TouchableOpacity> </View> )} {verifying && ( <View> <View> <TextInput value={code} placeholder="Code..." onChangeText={(code) => setCode(code)} /> </View> <TouchableOpacity onPress={handleVerify}> <Text>Verify Email</Text> </TouchableOpacity> </View> )} </View> ); }
your-app.html<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Clerk JavaScript Email + Password</title> </head> <body> <h1>Clerk JavaScript Email + Password</h1> <div id="auth-signup"> <input placeholder="email" id="email" type="email"></input> <input placeholder="password" id="password" type="password"></input> <button onclick="SignUp()">SignUp</button> </div> <div id="auth-verification" hidden="true"> <input placeholder="code" id="code" type="text"></input> <button onclick="VerifyEmailAddress()">Verify</button> </div> <div id="user-button" /> <script> const SignUp = async () => { const emailAddress = document.getElementById('email').value; const password = document.getElementById('password').value; const {client} = window.Clerk; try { await client.signUp.create({ emailAddress, password }); await client.signUp.prepareEmailAddressVerification(); //hide signup form document.getElementById('auth-signup').hidden = true; //show verification form document.getElementById('auth-verification').hidden = false; } catch (err) { console.log(err) } }; const VerifyEmailAddress = async () => { const code = document.getElementById('code').value; const {client, setActive} = window.Clerk; try { // Verify the email address. const verify = await client.signUp.attemptEmailAddressVerification({ code }); // User is created. Now, set the session to active. session is never null. await setActive({session: verify.createdSessionId}) } catch (err) { console.log(err) } } </script> // Script to load Clerk up <script src="src/script.js" async crossorigin="anonymous"></script> </body> </html>
Create sign in flow
In email/password authentication, the sign-in is a process that requires users to provide their email address and their password and authenticates them by creating a new session for the user.
app/sign-in/[[...sign-in]].page.tsx'use client' import * as React from "react"; import { useSignIn } from "@clerk/nextjs"; import { useRouter } from "next/navigation"; export default function SignInForm() { const { isLoaded, signIn, setActive } = useSignIn(); const [email, setEmail] = React.useState(""); const [password, setPassword] = React.useState(""); const router = useRouter(); // Handle the submission of the sign-in form const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!isLoaded) { return; } // Start the sign-in process using the email and password provided try { const completeSignIn = await signIn.create({ identifier: email, password, }); if (completeSignIn.status !== 'complete') { // The status can also be `needs_factor_on', 'needs_factor_two', or 'needs_identifier' // Please see https://clerk.com/docs/references/react/use-sign-in#result-status for more information console.log(JSON.stringify(completeSignIn, null, 2)); } if (completeSignIn.status === 'complete') { // If complete, user exists and provided password match -- set session active await setActive({ session: completeSignIn.createdSessionId }); // Redirect the user to a post sign-in route router.push('/'); } } catch (err: any) { // This can return an array of errors. // See https://clerk.com/docs/custom-flows/error-handling to learn about error handling console.error(JSON.stringify(err, null, 2)); } }; // Display a form to capture the user's email and password return ( <div> <form onSubmit={(e) => handleSubmit(e)}> <div> <label htmlFor="email">Email</label> <input onChange={(e) => setEmail(e.target.value)} id="email" name="email" type="email" value={email} /> </div> <div> <label htmlFor="password">Password</label> <input onChange={(e) => setPassword(e.target.value)} id="password" name="password" type="password" value={password} /> </div> <button type="submit">Sign In</button> </form> </div> ); }
pages/sign-in/[[...index]].tsximport { 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 router = useRouter(); // Handle the submission of the sign-in form const handleSubmit = async (e) => { e.preventDefault(); if (!isLoaded) { return; } // Start the sign-in process using the email and password provided try { const result = await signIn.create({ identifier: emailAddress, password, }); if (result.status === "complete") { // If complete, user exists and provided password match -- set session active await setActive({ session: result.createdSessionId }); // Redirect the user to a post sign-in route router.push("/") } else { // The status can also be `needs_factor_on', 'needs_factor_two', or 'needs_identifier' // Please see https://clerk.com/docs/references/react/use-sign-in#result-status for more information console.error(JSON.stringify(results, null, 2)); } } catch (err: any) { // This can return an array of errors. // See https://clerk.com/docs/custom-flows/error-handling to learn about error handling console.error(JSON.stringify(err, null, 2)); } }; // Display a form to capture the user's email and password return ( <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> ); }
signin.tsximport { useState } from "react"; import { useSignIn } from "@clerk/clerk-react"; export default function SignInForm() { const { isLoaded, signIn, setActive } = useSignIn(); const [emailAddress, setEmailAddress] = useState(""); const [password, setPassword] = useState(""); // Handle the submission of the sign-in form const handleSubmit = async (e) => { e.preventDefault(); if (!isLoaded) { return; } // Start the sign-in process using the email and password provided try { const completeSignIn = await signIn.create({ identifier: emailAddress, password, }); if (completeSignIn.status !== 'complete') { // The status can also be `needs_factor_on', 'needs_factor_two', or 'needs_identifier' // Please see https://clerk.com/docs/references/react/use-sign-in#result-status for more information console.log(JSON.stringify(completeSignIn, null, 2)); } if (completeSignIn.status === "complete") { // If complete, user exists and provided password match -- set session active await setActive({ session: completeSignIn.createdSessionId }); // redirect the user how you see fit. } } catch (err: any) { // This can return an array of errors. // See https://clerk.com/docs/custom-flows/error-handling to learn about error handling console.error(JSON.stringify(err, null, 2)); } }; return ( <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> ); }
app/routes/sign-in/$.tsximport { useState } from "react"; import { useSignIn } from "@clerk/remix"; export default function SignInForm() { const { isLoaded, signIn, setActive } = useSignIn(); const [emailAddress, setEmailAddress] = useState(""); const [password, setPassword] = useState(""); // Start the sign-in process using the email and password provided const handleSubmit = async (e) => { e.preventDefault(); if (!isLoaded) { return; } // Start the sign-in process using the email and password provided try { const completeSignIn = await signIn.create({ identifier: emailAddress, password, }); if (completeSignIn.status !== 'complete') { // The status can also be `needs_factor_on', 'needs_factor_two', or 'needs_identifier' // Please see https://clerk.com/docs/references/react/use-sign-in#result-status for more information console.log(JSON.stringify(completeSignIn, null, 2)); } if (completeSignIn.status === 'complete') { // If complete, user exists and provided password match -- set session active await setActive({ session: completeSignIn.createdSessionId }); } } catch (err: any) { // This can return an array of errors. // See https://clerk.com/docs/custom-flows/error-handling to learn about error handling console.error(JSON.stringify(err, null, 2)); } }; // Display a form to capture the user's email and password return ( <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> ); }
sign-in.tsximport { useState } from "react"; // Use React for Gatsby import { useSignIn } from "@clerk/clerk-react"; export default function SignInForm() { const { isLoaded, signIn, setActive } = useSignIn(); const [emailAddress, setEmailAddress] = useState(""); const [password, setPassword] = useState(""); // Handle the submission of the sign-in form const handleSubmit = async (e) => { e.preventDefault(); if (!isLoaded) { return; } // Start the sign-in process using the email and password provided try { const completeSignIn = await signIn.create({ identifier: emailAddress, password, }); if (completeSignIn.status !== 'complete') { // The status can also be `needs_factor_on', 'needs_factor_two', or 'needs_identifier' // Please see https://clerk.com/docs/references/react/use-sign-in#result-status for more information console.log(JSON.stringify(completeSignIn, null, 2)); } if (completeSignIn.status === 'complete') { // If complete, user exists and provided password match -- set session active await setActive({ session: completeSignIn.createdSessionId }); // Redirect the user to a post sign-in route router.push('/'); } } catch (err: any) { // This can return an array of errors. // See https://clerk.com/docs/custom-flows/error-handling to learn about error handling console.error(JSON.stringify(err, null, 2)); } }; // Display a form to capture the user's email and password return ( <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> ); }
SignUpScreen.tsximport React from "react"; import { Text, TextInput, TouchableOpacity, View } from "react-native"; import { useSignIn } from "@clerk/clerk-expo"; export default function SignInScreen() { const { signIn, setActive, isLoaded } = useSignIn(); const [emailAddress, setEmailAddress] = React.useState(""); const [password, setPassword] = React.useState(""); // Handle the submission of the sign-in form const onSignInPress = async () => { if (!isLoaded) { return; } // Start the sign-in process using the email and password provided try { const completeSignIn = await signIn.create({ identifier: emailAddress, password, }); if (completeSignIn.status !== 'complete') { // The status can also be `needs_factor_on', 'needs_factor_two', or 'needs_identifier' // Please see https://clerk.com/docs/references/react/use-sign-in#result-status for more information console.log(JSON.stringify(completeSignIn, null, 2)); } if (completeSignIn.status === 'complete') { // If complete, user exists and provided password match -- set session active await setActive({ session: completeSignIn.createdSessionId }); // Redirect the user to a post sign-in route router.push('/'); } } catch (err: any) { // This can return an array of errors. // See https://clerk.com/docs/custom-flows/error-handling to learn about error handling console.error(JSON.stringify(err, null, 2)); } }; // Display a form to capture the user's email and password return ( <View> <View> <TextInput autoCapitalize="none" value={emailAddress} placeholder="Email..." onChangeText={(emailAddress) => setEmailAddress(emailAddress)} /> </View> <View> <TextInput value={password} placeholder="Password..." secureTextEntry={true} onChangeText={(password) => setPassword(password)} /> </View> <TouchableOpacity onPress={onSignInPress}> <Text>Sign in</Text> </TouchableOpacity> </View> ); }
your-app.html<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Clerk JavaScript Email + Password</title> </head> <body> <h1>Clerk JavaScript Email + Password</h1> <div id="auth-signin"> <input placeholder="email" id="email" type="email"></input> <input placeholder="password" id="password" type="password"></input> <button onclick="SignIn()">SignIn</button> </div> <script> const SignIn = async () => { const emailAddress = document.getElementById('email').value; const password = document.getElementById('password').value; const {client} = window.Clerk; try { const signInAttempt = await client.signIn.create({ emailAddress, password }); if (signInAttempt.status === "complete") { await setActive({ session: signInAttempt.createdSessionId }); // redirect the user how you see fit. } else { /*Investigate why the login hasn't completed */ console.log(signInAttempt); } } catch (err) { console.log(err) } }; </script> // Script to load Clerk up <script src="src/script.js" async crossorigin="anonymous"></script> </body> </html>