Install & Compatibility
Where this runs
tested against v? · npm install
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
muslnode 18–226 runs
build_error
glibcnode 18–226 runs
build_error
Code
Verified usage
Verified import paths — ran on the pinned version, not inferred.
FormStrategy
✓ import { FormStrategy } from 'remix-auth-form';
✗ import FormStrategy from 'remix-auth-form';
const FormStrategy = require('remix-auth-form').FormStrategy;
remix-auth-form is an ESM-only package since v2.0.0. Using CommonJS `require` will result in errors. It is a named export, not a default export.
Authenticator
✓ import { Authenticator } from 'remix-auth';
✗ import { Authenticator } from 'remix-auth-form';
The `Authenticator` class is the core component of the `remix-auth` library, not `remix-auth-form`. Confusing the import source is a common mistake.
ActionFunctionArgs
✓ import type { ActionFunctionArgs } from '@remix-run/node';
✗ import type { ActionFunction } from 'remix';
Remix route types like `ActionFunction` were deprecated in favor of `ActionFunctionArgs` in Remix v1.3.0/v1.4.0, which became the standard in Remix 2.0. Ensure correct type imports for modern Remix applications.
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");
}
}
Errors
Common errors & fixes
TypeError: FormStrategy is not a constructor
Attempting to use `new FormStrategy()` after importing it incorrectly, often due to CommonJS `require` or incorrect named vs. default import in an ESM context.
fixEnsure you are using `import { FormStrategy } from 'remix-auth-form';` and that your project is configured for ESM, especially if using `remix-auth-form` v2.0.0 or higher. Cannot find module 'remix-auth-form' or its corresponding type declarations.
The package is not installed, the import path is wrong, or TypeScript cannot resolve types, possibly due to mismatched module systems (ESM/CJS).
fixRun `npm install remix-auth-form` or `yarn add remix-auth-form`. Verify the import path is exactly `remix-auth-form`. For TypeScript, ensure your `tsconfig.json` is configured for `"moduleResolution": "bundler"` or `"node16"` for modern Remix setups.
A strategy with the name 'form' is already in use.
You have called `authenticator.use()` with the default name ('form') more than once, or you've forgotten to provide a unique name for multiple instances of `FormStrategy`.
fixWhen using `authenticator.use()`, provide a unique string as the second argument if you're registering multiple strategies or multiple instances of the same strategy (e.g., `authenticator.use(new FormStrategy(...), "my-custom-form-strategy");`).
Audit
Dependencies
remix-authrequiredCore authentication library that this package extends as a strategy.