Skip to main content

useSignIn()

The useSignIn() hook exposes the underlying authentication primitives that power Wacht’s pre-built <SignInForm />. If your organization’s design system mandates pixel-perfect control over every input field, transition, and error state—or if you need to build a bespoke multi-step login modal—this hook provides the raw engine you need without forcing any UI upon you.

Import

import { useSignIn } from "@wacht/react-router";

Anatomy

Calling the hook returns an object containing the current status of the sign-in attempt, the active strategy, and the primary programmatic functions to progress the state machine.
loading
boolean
Indicates whether the SDK is actively managing a request state.
signIn
SignIn
signinAttempt
SigninAttempt | null
The current state of the sign-in attempt.
discardSignInAttempt
() => void
Clears the current sign-in attempt state.
setSignInAttempt
(attempt: SigninAttempt | null) => void
Setter function to manually override the sign-in attempt state.

Building a Custom Email / Password Flow

Here is a simplified example demonstrating how to construct a custom login form by leveraging the signIn object returned by the hook.
import { useSignIn } from "@wacht/react-router";
import { useState } from "react";
import { useNavigate } from "react-router";

export default function CustomSignIn() {
  const { loading, signIn } = useSignIn();
  const navigate = useNavigate();
  
  const [emailAddress, setEmailAddress] = useState("");
  const [password, setPassword] = useState("");
  const [error, setError] = useState("");

  if (loading) return <div>Loading...</div>;

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    setError("");

    try {
      // 1. Submit the credentials to the Wacht API
      // Since Wacht uses HTTP-only cookies, the session is established transparently
      // by the backend upon success. No `setActive` is required.
      const strategy = signIn.createStrategy("email");
      await strategy({
        email: emailAddress,
        password,
      });

      // 2. Redirect the user on success
      navigate("/dashboard");

    } catch (err: any) {
      setError(err.message || "Authentication failed");
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      {error && <div className="text-red-500 text-sm mb-4">{error}</div>}
      <input 
        type="email" 
        value={emailAddress} 
        onChange={(e) => setEmailAddress(e.target.value)} 
      />
      <input 
        type="password" 
        value={password} 
        onChange={(e) => setPassword(e.target.value)} 
      />
      <button type="submit">Sign In</button>
    </form>
  );
}

Security Warning

When bypassing the pre-built <SignInForm /> to build a custom implementation using useSignIn(), you take full responsibility for handling brute-force lockouts, rendering specific API error messages (like invalid_password), and orchestrating secondary authentication factors.