Skip to content
Blog

Session Verification

Sometimes a legitimate user logs in from a new laptop, and sometimes it’s someone who got hold of their credentials. Suspicious login protection helps you tell the difference. When it’s enabled, Tribe flags logins from unrecognized devices for users who have registered passkeys. Rather than blocking the login entirely, Tribe creates the session in an unverified state, and your app decides what to do next. The typical pattern is a verification gate that asks the user to confirm their identity with a passkey before they can proceed.

  1. Go to the Tribe dashboard
  2. Open your site’s Settings, Auth, Suspicious Login Protection
  3. Toggle on Enable suspicious login protection

This feature is opt-in and off by default. It only kicks in when two conditions are both true: the login comes from a device Tribe hasn’t seen before for this user, and the user has at least one registered passkey. If either condition is missing, the session is created as verified and sessionVerified will be true as usual.

The flow goes like this. A user logs in from a new device using any login method. Tribe recognizes the device is unfamiliar and checks whether the user has passkeys on file. If they do, the session gets created with verified: false, and the login response includes sessionVerified: false. Your app picks this up and shows a verification gate. The user taps their passkey, your code calls tribe.verifySession(), and the session flips to verified. From there, the app continues normally.

Every login method and getSession() includes sessionVerified in the response:

// After login
const { user, sessionVerified } = await tribe.login(email, password);
if (sessionVerified === false) {
// Show verification gate
}
// Or check later
const session = await tribe.getSession();
if (session?.sessionVerified === false) {
// Show verification gate
}
// Convenience method
const verified = await tribe.isSessionVerified();
await tribe.verifySession();
// Prompts the browser passkey dialog
// On success, the session is marked as verified
// Throws if browser doesn't support WebAuthn or user cancels
function VerificationGate({ children }) {
const [session, setSession] = useState(null);
const [loading, setLoading] = useState(true);
const [verifying, setVerifying] = useState(false);
const [error, setError] = useState("");
useEffect(() => {
tribe.getSession().then((s) => { setSession(s); setLoading(false); });
}, []);
if (loading) return <p>Loading...</p>;
if (!session) return <p>Not logged in</p>;
if (session.sessionVerified === false) {
const handleVerify = async () => {
setError("");
setVerifying(true);
try {
await tribe.verifySession();
setSession(await tribe.getSession());
} catch (err) {
if (err.name !== "NotAllowedError") setError(err.message);
setVerifying(false);
}
};
return (
<div>
<h2>Verify your identity</h2>
<p>We noticed a sign-in from a new device. Verify with your passkey to continue.</p>
{error && <p style={{ color: "red" }}>{error}</p>}
<button onClick={handleVerify} disabled={verifying}>
{verifying ? "Verifying..." : "Verify with passkey"}
</button>
</div>
);
}
return <>{children}</>;
}

You can use getAuthConfig() to find out whether the site has suspicious login protection turned on, and conditionally render verification-related UI based on that:

const config = await tribe.getAuthConfig();
if (config.suspiciousLoginProtection) {
// Site has this feature enabled — handle sessionVerified accordingly
}