Build a custom email/password authentication flow
This guide will walk you through how to build a custom email/password sign-up and sign-in flow.
Enable email and password authentication
To use email and password authentication, you first need to ensure they are enabled for your application.
- In the Clerk Dashboard, navigate to the User & authentication page.
- Enable Sign-up with email and Sign-in with email.
- Select the Password tab and enable Sign-up with password. Leave Require a password at sign-up enabled.
Sign-up flow
To sign up a user using their email, password, and email verification code, you must:
- Initiate the sign-up process by collecting the user's email address and password with the
signUp.password()
method. - Send a one-time code to the provided email address for verification with the
signUp.verifications.sendEmailCode()
method. - Collect the one-time code and verify it with the
signUp.verifications.verifyEmailCode()
method. - If the email address verification is successful, finalize the sign-up with the
signUp.finalize()
method to create the user and set the newly created session as the active session.
This example is written for Next.js App Router but it can be adapted for any React-based framework.
'use client'
import * as React from 'react'
import { useAuth, useSignUp } from '@clerk/nextjs'
import { useRouter } from 'next/navigation'
export default function SignUpPage() {
const { signUp, errors, fetchStatus } = useSignUp()
const { isSignedIn } = useAuth()
const handleSubmit = async (formData: FormData) => {
const email = formData.get('email') as string
const password = formData.get('password') as string
await signUp.password({
email,
password,
})
await signUp.verifications.sendEmailCode()
}
const handleVerify = async (formData: FormData) => {
const code = formData.get('code') as string
await signUp.verifications.verifyEmailCode({
code,
})
if (signUp.status === 'complete') {
await signUp.finalize({
navigate: () => {
router.push('/dashboard')
},
})
}
}
if (signUp.status === 'complete' || isSignedIn) {
return null
}
if (
signUp.status === 'missing_requirements' &&
signUp.unverifiedFields.includes('email_address')
) {
return (
<form action={handleVerify}>
<input type="text" name="code" placeholder="Enter your verification code" />
<button type="submit">Verify</button>
</form>
)
}
return (
<form action={handleSubmit}>
<input type="email" name="email" placeholder="Email" />
<input type="password" name="password" placeholder="Password" />
<button type="submit">Sign up</button>
</form>
)
}
Sign-in flow
To authenticate a user using their email and password, you must:
- Initiate the sign-in process by collecting the user's email address and password with the
signIn.password()
method. - If the attempt is successful, finalize the sign-in with the
signIn.finalize()
method to set the newly created session as the active session.
This example is written for Next.js App Router but it can be adapted for any React-based framework.
'use client'
import * as React from 'react'
import { useAuth, useSignIn } from '@clerk/nextjs'
import { useRouter } from 'next/navigation'
export default function SignInPage() {
const { signIn, errors, fetchStatus } = useSignIn()
const { isSignedIn } = useAuth()
const handleSubmit = async (formData: FormData) => {
const email = formData.get('email') as string
const password = formData.get('password') as string
await signIn.password({
email,
password,
})
if (signIn.status === 'complete') {
await signIn.finalize({
navigate: () => {
router.push('/dashboard')
},
})
}
}
if (signIn.status === 'complete' || isSignedIn) {
return null
}
return (
<form action={handleSubmit}>
<input type="email" name="email" placeholder="Email" />
<input type="password" name="password" placeholder="Password" />
<button type="submit">Sign in</button>
</form>
)
}
Feedback
Last updated on