Remix Auth Form Strategy

3.0.0 · active · verified Wed Apr 22

remix-auth-form is a specialized strategy for the Remix Auth library, designed to handle authentication via any HTML form. It provides the `FormData` instance and the original `Request` object directly to the `verify` callback, enabling flexible input handling beyond traditional username/password schemes. This allows developers to include additional fields as needed for their authentication flow. The package is currently at v3.0.0, having recently updated to support Remix Auth v4. Releases appear to be driven by breaking changes in `remix-auth` or `Remix` itself, ensuring compatibility with the latest ecosystem features. It supports both Node.js and Cloudflare runtimes, making it versatile for various deployment targets.

Common errors

Warnings

Install

Imports

Quickstart

This quickstart demonstrates how to set up `remix-auth-form` with `remix-auth`, define a custom authentication logic using form data, and integrate it into a Remix `action` function for handling user login. It showcases form data access, basic validation, and redirection upon success or failure.

import { Authenticator } from "remix-auth";
import { sessionStorage } from "~/services/session.server";
import { FormStrategy } from "remix-auth-form";
import { redirect, type ActionFunctionArgs } from "@remix-run/node";

// Placeholder for your User type and database logic
interface User { id: string; username: string; }
async function findOrCreateUser(username: string, hashedPassword: string): Promise<User> {
  console.log(`Finding or creating user: ${username} with hashed password: ${hashedPassword}`);
  // In a real app, you'd interact with your database here.
  // For this example, we'll just return a dummy user.
  return { id: 'some-user-id', username: username };
}

// This would typically come from a utility, e.g., 'bcrypt'
async function hash(password: string): Promise<string> {
  return `hashed-${password}`;
}

// You would define your session storage here
export let authenticator = new Authenticator<User>(sessionStorage);

authenticator.use(
  new FormStrategy(async ({ form, request }) => {
    let username = form.get("username");
    let password = form.get("password");

    // Basic validation (use a library like Zod for robust validation)
    if (typeof username !== "string" || username.length === 0) {
      throw new Error("Username must be a non-empty string");
    }
    if (typeof password !== "string" || password.length === 0) {
      throw new Error("Password must be a non-empty string");
    }

    let hashedPassword = await hash(password);
    let user = await findOrCreateUser(username, hashedPassword);

    return user;
  }),
  // Optional: provide a custom name for the strategy if using multiple form strategies
  "user-pass"
);

export async function action({ request }: ActionFunctionArgs) {
  try {
    let user = await authenticator.authenticate("user-pass", request, {
      successRedirect: "/dashboard",
      failureRedirect: "/login?error=true",
      throwOnError: true,
    });
    // If successful, user is authenticated and session is set.
    // The successRedirect handles the actual redirect.
    return user; // Should not be reached if successRedirect is set
  } catch (error) {
    // If throwOnError is true, strategy errors will be re-thrown here.
    // Handle authentication failures, e.g., log the error or return a specific response.
    console.error("Authentication error:", error);
    // The failureRedirect would handle the UI redirect to login page.
    return redirect("/login?error=true");
  }
}

view raw JSON →