Sign In with Credentials

The field names passed to signIn("credentials", ...) must match the configured provider fields. With redirect: false, handle the returned result and show a generic error. The actual password verification occurs server-side in authorize.

Credentials form
import { useState } from "react";
import { signIn } from "next-auth/react";

export default function CredentialsForm() {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [error, setError] = useState("");
  const [busy, setBusy] = useState(false);

  async function submit(event) {
    event.preventDefault();
    setError("");
    setBusy(true);
    try {
      const result = await signIn("credentials", {
        email, password, redirect: false, callbackUrl: "/dashboard",
      });
      if (result?.error) setError("Invalid email or password.");
      else if (result?.url) window.location.assign(result.url);
    } catch {
      setError("Unable to sign in. Please try again.");
    } finally {
      setBusy(false);
    }
  }

  return <form onSubmit={submit}>
    <label>Email <input type="email" autoComplete="email" required value={email} onChange={e => setEmail(e.target.value)} /></label>
    <label>Password <input type="password" autoComplete="current-password" required value={password} onChange={e => setPassword(e.target.value)} /></label>
    <button disabled={busy}>{busy ? "Signing in…" : "Sign in"}</button>
    {error && <p role="alert">{error}</p>}
  </form>;
}
💡 Do not log the form values. This example uses a generic error message and a loading state.