Password reset
Let people who forgot their password get back in, safely.
How it works
- The user enters their email on the Forgot password page.
- If an account exists, a 6-digit code is emailed. The page says the same thing either way.
- The user enters the code and a new password.
- The password is changed, the email is marked verified, and every existing session is signed out.
Two design choices are worth knowing about.
The response never reveals whether an email has an account. Otherwise anyone could check whether [email protected] uses your app.
All sessions end on reset. People usually reset because they think someone else may know their password. If that someone is already signed in, the reset needs to kick them out too.
Using the hosted pages
The sign-in page has a Forgot password? link to /forgot-password. To link there yourself:
tsx
"use client";
import { useAuthClient } from "@daywalker/auth/react";
export function ForgotLink() {
const client = useAuthClient();
return <a href={client.hostedUrl("forgot-password", window.location.href)}>Forgot password?</a>;
}Building it into your own UI
tsx
"use client";
import { useState } from "react";
import { useAuth, AuthError } from "@daywalker/auth/react";
export function ResetPassword() {
const { requestPasswordReset, resetPassword } = useAuth();
const [email, setEmail] = useState<string | null>(null);
const [message, setMessage] = useState("");
if (!email)
return (
<form onSubmit={async (e) => {
e.preventDefault();
const value = new FormData(e.currentTarget).get("email") as string;
await requestPasswordReset(value);
setEmail(value);
}}>
<input name="email" type="email" autoComplete="email" required />
<button>Send code</button>
</form>
);
return (
<form onSubmit={async (e) => {
e.preventDefault();
const f = new FormData(e.currentTarget);
try {
await resetPassword({ email, code: f.get("code") as string, password: f.get("password") as string });
setMessage("Password changed. Please sign in again.");
} catch (err) {
setMessage(err instanceof AuthError ? err.message : "Try again");
}
}}>
<p>If {email} has an account, we sent it a code.</p>
<input name="code" inputMode="numeric" autoComplete="one-time-code" maxLength={6} required />
<input name="password" type="password" autoComplete="new-password" required />
<button>Set new password</button>
{message && <p role="status">{message}</p>}
</form>
);
}Errors you might see
code |
Meaning |
|---|---|
invalid_code |
Wrong, expired, already used, or out of guesses. Ask for a new one. |
password_too_short |
Below the instance's minimum (8 by default). The code is not used up, so the user can retry. |
rate_limited |
Too many attempts. Wait and try again. |