Skip to main content

useSignIn()

The useSignIn() hook exposes the underlying authentication primitives utilized by the pre-built <SignInForm /> component. This hook facilitates the development of custom authentication interfaces, enabling precise control over input handling, state transitions, and error management without relying on predefined UI components.

Hook Import

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

Hook Interface

The hook returns an object detailing the current status of the sign-in attempt, the active authentication strategy, and the methods required to progress the state machine.
loading
boolean
Indicates whether the SDK is actively processing a network request or managing internal state transitions.
signIn
SignIn
signinAttempt
SigninAttempt | null
The active context state of the current sign-in execution.
discardSignInAttempt
() => void
Terminates and clears the current sign-in attempt context from memory.
setSignInAttempt
(attempt: SigninAttempt | null) => void
Direct mutation method to override the existing sign-in attempt state representation.

Implementation Guidelines

Developing a Custom Credential Interface

The following implementation demonstrates the construction of a custom credential submission interface utilizing the signIn object:
import { useSignIn } from "@wacht/tanstack-router";
import { useState } from "react";
import { useNavigate } from "@tanstack/react-router";

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

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

    try {
      const emailStrategy = signIn.createStrategy("email");
      await emailStrategy({
        email: emailAddress,
        password,
      });

      // The Wacht API transparently sets an HTTP-only session cookie upon success.
      navigate({ to: "/dashboard" });
    } catch (err: any) {
      setError(err.message || "Authentication negotiation failed.");
    }
  };

  return (
    <form onSubmit={handleSubmit} className="flex flex-col gap-4">
      {error && <div className="text-red-700 font-medium text-sm border border-red-200 p-2 rounded bg-red-50">{error}</div>}
      <input 
        type="email" 
        value={emailAddress} 
        onChange={(e) => setEmailAddress(e.target.value)}
        className="border p-2 rounded"
      />
      <input 
        type="password" 
        value={password} 
        onChange={(e) => setPassword(e.target.value)} 
        className="border p-2 rounded"
      />
      <button type="submit" disabled={loading} className="bg-blue-600 text-white p-2 rounded">
        {loading ? "Authenticating..." : "Sign In"}
      </button>
    </form>
  );
}

Security Considerations

Implementing custom authentication interfaces via useSignIn() bypasses the protections embedded within the pre-built <SignInForm /> component. Consequently, the consuming application is directly responsible for rendering granular API error messages (e.g., invalid_password), orchestrating multi-factor authentication steps, and appropriately handling brute-force lockouts.