MFA Fallback / Custom Authentication
If passkey creation fails, users can fall back to a custom authentication method provided by your CIAM (Customer Identity and Access Management) system or your own authenticaion backend service.
Once authenticated, the backend issues an authorization token, which is then passed to LoginID to complete the MFA process.
This example can be used for both user signup (first-time registration) and signin (subsequent logins).
- Attempt to register a passkey.
- If passkey fails, fallback to custom authentication (e.g., password or other methods).
- The backend verifies the authentication request and requests an authorization token from LoginID. This is done by making a POST request to /fido2/v2/mgmt/grant/external-auth.
- The frontend sends this token to LoginID to complete MFA authentication.

Prerequisites
- Create an application to obtain a base URL. The SDK uses this base URL to interact with the LoginID authentication service.
- Create an API key with at least the external-verify scope. You’ll need this to request authorization tokens from your backend.
Setup SDK
- Javascript
npm i @loginid/websdk3
Import and initialize an instance:
import { LoginIDMfa } from "@loginid/websdk3";
const lid = new LoginIDMfa({
baseUrl: process.env.LOGINID_BASE_URL,
});
Full Example
Handles MFA session initiation and passkey registration. If passkey registration fails, it triggers a callback to show the next step.
import { LoginIDMfa } from "@loginid/websdk3";
const config = {
baseUrl: process.env.REACT_APP_LOGINID_BASE_URL
};
const mfa = new LoginIDMfa(config);
const PasskeySignup = ({ onFallback }) => {
const [username, setUsername] = useState("");
const [error, setError] = useState("");
const handleSignup = async () => {
try {
// Step 1: Begin MFA session
const session = await mfa.beginFlow(username);
// Step 2: Attempt Passkey Registration
await mfa.performAction("passkey:reg");
console.log("Passkey registration successful.");
} catch (err) {
console.warn("Passkey registration failed, switching to custom authentication.");
onFallback(username); // Trigger fallback authentication
}
};
};
Handles fallback authentication with a CIAM system or custom backend. The backend returns an authorization token, which is passed to LoginID for authentication.
import { LoginIDMfa } from "@loginid/websdk3";
const config = {
baseUrl: process.env.REACT_APP_LOGINID_BASE_URL
};
const mfa = new LoginIDMfa(config);
const CustomAuthSignup = ({ username }) => {
const [customAuthData, setCustomAuthData] = useState("");
const [error, setError] = useState("");
const handleCustomAuth = async () => {
try {
// Step 3: Authenticate with CIAM or Custom Backend
const response = await fetch("/api/signup", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ username, authData: customAuthData }),
});
if (!response.ok) throw new Error("Failed to authenticate with custom provider");
const { authToken } = await response.json();
// Step 4: Perform External Authentication with LoginID
await mfa.performAction("external", { payload: authToken });
console.log("Custom authentication completed successfully.");
} catch (err) {
console.error("Custom authentication error:", err);
setError("Failed to complete signup. Please try again.");
}
};
};
This component orchestrates the signup process. It starts with passkey signup, and if it fails, it switches to custom authentication.
import PasskeySignup from "./PasskeySignup";
import CustomAuthSignup from "./CustomAuthSignup";
const SignupFlow = () => {
const [fallbackUser, setFallbackUser] = useState(null);
return (
<div>
{fallbackUser ? (
<CustomAuthSignup username={fallbackUser} />
) : (
<PasskeySignup onFallback={(username) => setFallbackUser(username)} />
)}
</div>
);
};