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.
TOTPStrategy
✓ import { TOTPStrategy } from 'remix-auth-totp';
✗ const TOTPStrategy = require('remix-auth-totp');
remix-auth-totp primarily uses named exports. Direct CommonJS require without destructuring will not work.
TOTPStrategyOptions
✓ import type { TOTPStrategyOptions } from 'remix-auth-totp';
✗ import { TOTPStrategyOptions } from 'remix-auth-totp';
This is a TypeScript type interface; use `import type` for clarity and better tree-shaking where supported.
TOTPError
✓ import { TOTPError } from 'remix-auth-totp';
✗ const { TOTPError } = require('remix-auth-totp');
Use `TOTPError` for catching specific errors thrown by the strategy during authentication.
Demonstrates setting up `remix-auth-totp` with `remix-auth` to initialize the strategy with `secret` and `sendTOTP` callbacks, and handle an authentication attempt in a Remix action.
import { Authenticator } from "remix-auth";
import { TOTPStrategy } from "remix-auth-totp";
import { createCookieSessionStorage, redirect } from "@remix-run/node";
interface User {
id: string;
email: string;
}
// 1. Setup session storage
const sessionStorage = createCookieSessionStorage({
cookie: {
name: "__session",
httpOnly: true,
sameSite: "lax",
path: "/",
secrets: [process.env.SESSION_SECRET ?? 'a_secret_key'], // Replace with actual secret
secure: process.env.NODE_ENV === "production",
},
});
// 2. Initialize Authenticator
export const authenticator = new Authenticator<User>(sessionStorage);
// Mock database for TOTP secrets (replace with your actual database)
const userTotpSecrets = new Map<string, string>();
userTotpSecrets.set("test@example.com", process.env.TOTP_USER_SECRET ?? 'A_VERY_SECURE_SECRET');
// 3. Register the TOTP Strategy
authenticator.use(
new TOTPStrategy(
{
secret: async ({ email }) => {
// Fetch the user's TOTP secret from your database
const secret = userTotpSecrets.get(email);
if (!secret) {
throw new Error(`TOTP not configured for ${email}.`);
}
return secret;
},
sendTOTP: async ({ email, code, magicLink, request }) => {
// In a real app, send `code` or `magicLink` via email/SMS to `email`.
console.log(`Sending code ${code} or magic link to ${email}`);
// Example: await sendEmail({ to: email, subject: "Your TOTP Code", body: `Code: ${code}. Or login: ${magicLink}` });
},
// You can add other options like `maxAge`, `issuer`, `magicLinkPath`
},
async ({ email, code, magicLink }) => {
// Verify the user and return the user object upon successful authentication.
// This is where you would fetch the user from your DB and return it.
if (email === "test@example.com" && (code === "123456" || magicLink)) { // Simplified logic
return { id: "user-abc", email: "test@example.com" };
}
throw new Error("Invalid TOTP or Magic Link.");
}
),
"totp" // Unique name for this strategy
);
// 4. Example Remix Action (e.g., in `app/routes/login.tsx`)
export async function action({ request }: { request: Request }) {
try {
return await authenticator.authenticate("totp", request, {
successRedirect: "/dashboard",
failureRedirect: "/login?error=true",
});
} catch (error) {
if (error instanceof Response && error.status >= 300 && error.status < 400) {
throw error; // Propagate redirects from authenticator (e.g., magic link sent)
}
console.error("Login failed:", error);
return redirect("/login?error=true");
}
}
Errors
Common errors & fixes
TypeError: Buffer is not a constructor
Running an older version of `remix-auth-totp` (prior to v3.4.2) on Node.js v20 or a similar runtime environment that has removed the global Buffer constructor.
fixUpgrade `remix-auth-totp` to v3.4.2 or higher to utilize `Uint8Array` and Web Crypto API for compatibility with modern Node.js versions.
Error: TOTPStrategy: secret is a required option
The `secret` callback function was not provided or returned null/undefined in the `TOTPStrategy` constructor options.
fixEnsure the `TOTPStrategy` constructor is provided with a `secret` async function that reliably retrieves the user's unique TOTP secret based on the input (e.g., email).
ReferenceError: TOTPStrategy is not defined
Incorrect CommonJS `require` syntax or incorrect named import for `TOTPStrategy` in an ES module context.
fixUse a named import: `import { TOTPStrategy } from 'remix-auth-totp';` or for CommonJS: `const { TOTPStrategy } = require('remix-auth-totp');`. Authentication failed: Error: Invalid TOTP code or Magic Link.
The `verify` callback function provided to the `TOTPStrategy` threw an error, indicating that the submitted code or magic link was incorrect, expired, or the associated user could not be found.
fixDebug the `verify` callback. Check if the submitted `code` matches the expected TOTP, if the `magicLink` is valid and not expired, and if the user data used for verification is correct.
Audit
Dependencies
remix-authrequiredCore authentication library that remix-auth-totp extends.