ForgeWP

Choose a New Password

Read the reset link, submit a new password, and handle expired or reused keys.

Choose a new password

The reset page receives the login and key query parameters from a recovery email. Call resetPassword(login, key, password) to submit the new password. The hook returns a boolean promise and exposes action failures through error.

A reset key is a temporary credential

Use the original email link. Do not display its key in status messages or include it in analytics events or shared logs. A reset key is separate from an email-verification token.

Add a reset-page component

src/components/NewPassword.tsx
1import { useEffect, useState, type FormEvent } from "react"
2import { WpAuthProvider, useWpAuth } from "@forgewp/auth"
3
4function NewPasswordFields() {
5  const { resetPassword, loading, error } = useWpAuth()
6  const [link, setLink] = useState<{ login: string; key: string } | null>(null)
7  const [password, setPassword] = useState("")
8  const [complete, setComplete] = useState(false)
9
10  useEffect(() => {
11    const params = new URLSearchParams(window.location.search)
12    setLink({ login: params.get("login") || "", key: params.get("key") || "" })
13  }, [])
14
15  async function handleSubmit(event: FormEvent<HTMLFormElement>) {
16    event.preventDefault()
17    if (!link?.login || !link.key || !password) return
18    if (await resetPassword(link.login, link.key, password)) {
19      setPassword("")
20      setComplete(true)
21    }
22  }
23
24  if (!link) return <p role="status">Reading your reset link…</p>
25  if (!link.login || !link.key) {
26    return (
27      <p role="alert">
28        Open the complete reset link from your email or request a new one.
29      </p>
30    )
31  }
32  if (complete)
33    return <p role="status">Reset completed. You can now sign in.</p>
34
35  return (
36    <form onSubmit={handleSubmit}>
37      <label>
38        New password
39        <input
40          type="password"
41          autoComplete="new-password"
42          required
43          value={password}
44          onChange={(event) => setPassword(event.target.value)}
45        />
46      </label>
47      <button type="submit" disabled={loading}>
48        {loading ? "Resetting…" : "Save new password"}
49      </button>
50      {error && <p role="alert">{error}</p>}
51    </form>
52  )
53}
54
55export default function NewPassword() {
56  return (
57    <WpAuthProvider>
58      <NewPasswordFields />
59    </WpAuthProvider>
60  )
61}

Mount this component on your theme's reset-password route. It reads the query in an effect so browser-only access happens after the initial React render. The example requires a nonempty password; it does not add a strength policy. If your project needs confirmation, strength guidance, or additional password rules, implement the controls and corresponding server policy deliberately.

Expected outcomes

Table · 2 columns
Input or link state
Outcome
Missing login, key, or password
Request cannot complete
Key belongs to another login
WordPress rejects it
Invalid, expired, or reused key
Show the action error and offer a new recovery request
Valid key and new password
WordPress changes the password

The generated endpoint delegates validation to WordPress check_password_reset_key() and changes the password only after that check succeeds. Key expiry and invalidation follow WordPress and installed plugin policy. The endpoint does not automatically sign the visitor in after reset.

Preview completion is a simulation

The preview checks the mock login/token pair and consumes a matching token once. It does not change a WordPress password hash or enforce real key expiry. Local login remains the documented mock-password simulation.

An empty password or mismatched login does not consume a valid mock token. If the preview token store is malformed, the action fails rather than completing a reset.

Verify the installed workflow

Request a real email, follow the generated route, submit the new password, and test login with the new credentials. Check an expired/invalid key and a second use of the same link. Verify recovery mail, cookies, routing, and any plugin password rules separately from the local simulation.

Return to Request a Reset Link when another email is needed.