Multi-Factor Recovery
All Tribe auth methods are fully pseudonymous — no email or identity is ever stored. If a user loses access to their only auth method, they’re locked out. For password users, there are two built-in recovery paths: password reset (enter email, get a reset link, set a new password) and magic link (enter email, get a login link, signed in directly). Both verify the email against the pseudonymous ID without ever storing it. For wallet and social login users, account linking provides a safety net.
Account linking lets users attach additional auth methods to their account. Each linked method works on its own, so losing one doesn’t mean losing the account.
How it differs from MFA
Section titled “How it differs from MFA”Account linking and multi-factor authentication sound similar but serve opposite purposes. MFA makes it harder for someone else to break in by requiring multiple factors at sign-in. Account linking makes it harder for the legitimate user to get locked out by giving them multiple independent paths back in.
| MFA (e.g. TOTP) | Account linking | |
|---|---|---|
| Purpose | Harder to break in | Never get locked out |
| Both required? | Yes | No, any single linked method is sufficient |
| Adds friction? | Yes | No |
Link methods
Section titled “Link methods”import { Tribe } from "@tribecloud/sdk";
// See what's already linkedconst credentials = await tribe.getLinkedCredentials();// [{ id, provider: "wallet", walletAddress: "7fXk...", createdAt }]
// Link a Solana wallet (prompts wallet popup)const updated = await tribe.linkWallet();
// Link Google (shows Google One Tap popup)const updated = await tribe.linkGoogle();
// Link GitHub, Discord, or Twitter (redirects away and back)tribe.linkOAuth("github");Unlink a method
Section titled “Unlink a method”const updated = await tribe.unlinkCredential(credentialId);// Throws if it's the last recovery method — can't lock the user outDetect successful OAuth link
Section titled “Detect successful OAuth link”When linkOAuth() redirects the user back to your app, the URL includes parameters indicating whether the link succeeded:
const params = new URLSearchParams(window.location.search);const linked = params.get("tribe_linked"); // "github" | "discord" | etc.const error = params.get("tribe_link_error"); // "already_linked" | null
if (linked) { alert(`${linked} linked successfully!`); params.delete("tribe_linked"); history.replaceState({}, "", `${location.pathname}?${params}`);}Recovery prompt (React)
Section titled “Recovery prompt (React)”For users who signed in through a pseudonymous method and haven’t linked any backup, showing a prompt right after their first login is the simplest way to encourage them to protect their account:
function RecoveryPrompt({ credentials }) { if (credentials.length > 0) return null;
return ( <div role="alert"> <strong>Add a recovery method</strong> <p>If you lose access to your current login, you won't be able to recover your account.</p> <button onClick={() => tribe.linkWallet()}>Link a wallet</button> <button onClick={() => tribe.linkOAuth("github")}>Link GitHub</button> <button onClick={() => tribe.linkGoogle()}>Link Google</button> </div> );}