Skip to main content
Version: Next

Create your own UI

When using the email auth provider, users log in with their email address and a password. On signup, Wasp validates the data and sends a verification email. The user account is not active until the user clicks the link in the verification email. Also, the user can reset their password through a similar flow.

tip

Read more about the default email and password validation rules in the auth overview docs.

Even though Wasp offers premade Auth UI for your authentication flows, there are times when you might want more customization, so we also give you the option to create your own UI and call Wasp's auth actions from your own code, similar to how Auth UI does it under the hood.

Handling the internationalized email input

We use type="text" with inputMode="email" and autoComplete="email" because it allows Unicode / international characters, while type=email only allows ASCII / english letters.

Example code​

Below you can find a starting point for making your own UI in the client code. This example has all the necessary components to handle login, signup, email verification, and the password reset flow. You can customize any of its look and behaviour, just make sure to call the functions imported from wasp/client/auth.

src/pages/auth.jsx
import {
login,
requestPasswordReset,
resetPassword,
signup,
verifyEmail,
} from 'wasp/client/auth'

import { useState } from 'react'
import { useNavigate } from 'react-router'

// This will be shown when the user wants to log in
export function LoginPage() {
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const [error, setError] = useState(null)
const navigate = useNavigate()

async function handleSubmit(event) {
event.preventDefault()
setError(null)
try {
await login({ email: email.trim(), password })
navigate('/')
} catch (error) {
setError(error)
}
}

return (
<form onSubmit={handleSubmit}>
{error && <p>Error: {error.message}</p>}

<input
type="text"
inputMode="email"
autoComplete="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Email"
/>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="Password"
/>
<button type="submit">Log In</button>
</form>
)
}

// This will be shown when the user wants to sign up
export function SignupPage() {
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const [error, setError] = useState(null)
const [needsConfirmation, setNeedsConfirmation] = useState(false)

async function handleSubmit(event) {
event.preventDefault()
setError(null)
try {
await signup({ email: email.trim(), password })
setNeedsConfirmation(true)
} catch (error) {
console.error('Error during signup:', error)
setError(error)
}
}

if (needsConfirmation) {
return (
<p>
Check your email for the confirmation link. If you don't see it, check
spam/junk folder.
</p>
)
}

return (
<form onSubmit={handleSubmit}>
{error && <p>Error: {error.message}</p>}

<input
type="text"
inputMode="email"
autoComplete="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Email"
/>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="Password"
/>
<button type="submit">Sign Up</button>
</form>
)
}

// This will be shown has clicked on the link in their
// email to verify their email address
export function EmailVerificationPage() {
const [error, setError] = useState(null)
const navigate = useNavigate()

async function handleClick() {
setError(null)
try {
// The token is passed as a query parameter
const token = new URLSearchParams(window.location.search).get('token')
if (!token) throw new Error('Token not found in URL')
await verifyEmail({ token })
navigate('/')
} catch (error) {
console.error('Error during email verification:', error)
setError(error)
}
}

return (
<>
{error && <p>Error: {error.message}</p>}

<button onClick={handleClick}>Verify email</button>
</>
)
}

// This will be shown when the user wants to reset their password
export function RequestPasswordResetPage() {
const [email, setEmail] = useState('')
const [error, setError] = useState(null)
const [needsConfirmation, setNeedsConfirmation] = useState(false)

async function handleSubmit(event) {
event.preventDefault()
setError(null)
try {
await requestPasswordReset({ email: email.trim() })
setNeedsConfirmation(true)
} catch (error) {
console.error('Error during requesting reset:', error)
setError(error)
}
}

if (needsConfirmation) {
return (
<p>
Check your email for the confirmation link. If you don't see it, check
spam/junk folder.
</p>
)
}

return (
<form onSubmit={handleSubmit}>
{error && <p>Error: {error.message}</p>}

<input
type="text"
inputMode="email"
autoComplete="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Email"
/>

<button type="submit">Send password reset</button>
</form>
)
}

// This will be shown when the user clicks on the link in their
// email to reset their password
export function PasswordResetPage() {
const [error, setError] = useState(null)
const [newPassword, setNewPassword] = useState('')
const navigate = useNavigate()

async function handleSubmit(event) {
event.preventDefault()
setError(null)
try {
// The token is passed as a query parameter
const token = new URLSearchParams(window.location.search).get('token')
if (!token) throw new Error('Token not found in URL')
await resetPassword({ token, password: newPassword })
navigate('/')
} catch (error) {
console.error('Error during password reset:', error)
setError(error)
}
}

return (
<form onSubmit={handleSubmit}>
{error && <p>Error: {error.message}</p>}

<input
type="password"
autoComplete="new-password"
value={newPassword}
onChange={(e) => setNewPassword(e.target.value)}
placeholder="New password"
/>

<button type="submit">Reset password</button>
</form>
)
}

API Reference​

You can import the following functions from wasp/client/auth:

login()​

API reference

login »

Log the user in with their email and password.

signup()​

API reference

signup »

Sign the user up with their email and password, and send the verification email.

verifyEmail()​

API reference

verifyEmail »

Verify the user's email with the token from the verification email.

requestPasswordReset()​

API reference

requestPasswordReset »

Send the user a password reset email.

resetPassword()​

API reference

resetPassword »

Set the user's new password with the token from the password reset email.