Login & Logout
Use the built-in form or connect a custom login interface to Auth actions.
Login and logout
Put your account interface inside WpAuthProvider. Use WpLoginForm when its ready-made controls fit the design, or call useWpAuth().login() from your own form.
1import { WpAuthProvider, WpLoginForm } from "@forgewp/auth"
2
3export default function AccountLogin() {
4 return (
5 <WpAuthProvider>
6 <WpLoginForm className="max-w-md" />
7 </WpAuthProvider>
8 )
9}WpLoginForm accepts className and an optional onSuccess callback. It does not accept a redirectTo prop. For an explicit destination, use the custom login() call below. Cookie-mode production login normally reloads or navigates as part of the action; do not rely on a callback running before that navigation.
Choose your starting point
Approach Best fit What you supply WpLoginForm A ready-made login interface Provider scope, placement, and optional className Custom form with login() Your own controls, feedback, or destination Input state, submission handler, and loading/error UI |
|---|
Keep the first version small
Start with the built-in form to check the account workflow. Switch to a custom form when the interface needs different controls or behavior.
Build a custom form
login(credential, password, redirectUrl?) returns Promise<boolean>. A credential is the username or email entered by the visitor; the active loginField policy decides which is accepted.
1import { useState, type FormEvent } from "react"
2import { WpAuthProvider, useWpAuth } from "@forgewp/auth"
3
4function LoginFields() {
5 const [credential, setCredential] = useState("")
6 const [password, setPassword] = useState("")
7 const { login, loading, error, loginField } = useWpAuth()
8 const label =
9 loginField === "emailOnly"
10 ? "Email"
11 : loginField === "usernameOnly"
12 ? "Username"
13 : "Username or email"
14
15 async function handleSubmit(event: FormEvent<HTMLFormElement>) {
16 event.preventDefault()
17 const signedIn = await login(credential, password)
18 if (signedIn) setPassword("")
19 }
20
21 return (
22 <form onSubmit={handleSubmit}>
23 <label>
24 {label}
25 <input
26 name="credential"
27 type={loginField === "emailOnly" ? "email" : "text"}
28 autoComplete="username"
29 value={credential}
30 onChange={(event) => setCredential(event.target.value)}
31 required
32 />
33 </label>
34 <label>
35 Password
36 <input
37 name="password"
38 type="password"
39 autoComplete="current-password"
40 value={password}
41 onChange={(event) => setPassword(event.target.value)}
42 required
43 />
44 </label>
45 <button type="submit" disabled={loading}>
46 {loading ? "Signing in…" : "Sign in"}
47 </button>
48 {error && <p role="alert">{error}</p>}
49 </form>
50 )
51}
52
53export default function CustomAccountLogin() {
54 return (
55 <WpAuthProvider>
56 <LoginFields />
57 </WpAuthProvider>
58 )
59}To choose a destination, pass a developer-controlled URL as the third argument, for example login(credential, password, "/account"). Choose a real route in your theme; this argument does not create a WordPress Page. Use your site's actual path when WordPress is installed under a subdirectory. Do not pass unreviewed user input as a redirect destination.
If login fails, it returns false and updates error. Read that error during rendering so it reflects the latest hook state. The form above keeps the visitor's input available to correct; a successful login clears its password state if the current page remains mounted.
Cookie-mode login flow
Keep navigation intentional
Use a destination supplied by your theme. A redirect URL selects an existing route; it does not create a Page or grant permission to view it.
Sign out
Call logout() from the same provider scope as your account display. It returns Promise<void>; render error for feedback rather than expecting a success boolean. The first-login example shows a complete user display and logout button.
In local preview, signing out clears the browser's mock session. In WordPress cookie mode, Auth sends a POST request to /wp-json/forgewp/v1/auth/logout. A successful response clears local user state and reloads the page. If the server rejects the request or the connection fails, the current user state is retained, an error is shown through the hook, and the page stays available for another attempt.
JWT-mode logout clears the locally stored token and user display. Server-side token revocation depends on the JWT backend; local removal alone does not revoke a previously issued token.
WordPress installed under a subdirectory
Both provider and standalone cookie calls preserve the path from the generated home setting. A home URL such as https://example.test/members/ produces /members/wp-json/forgewp/v1/auth/login. Root installations use /wp-json/....
An explicitly supplied API base takes priority and is normalized without a trailing slash. Supply the WordPress base URL, such as https://backend.test/wordpress, rather than a URL already ending in /wp-json. Cross-origin cookie behavior needs deployment-specific configuration; a working same-origin preview does not establish it.
Check the complete workflow
In preview, test the mock login identifier policy, visible errors, and logout state. On an installed theme, test correct and incorrect credentials, a page reload after login, a rejected logout request, and protected content after successful logout. These are separate checks because the preview does not validate WordPress password hashes or server cookies.