{
    "componentChunkName": "component---src-pages-blog-markdown-remark-fields-slug-js",
    "path": "/blog/mfa-react",
    "result": {"data":{"markdownRemark":{"html":"<h2 id=\"add-mfa-to-react-fast-by-using-supertokens\" style=\"position:relative;\"><a href=\"#add-mfa-to-react-fast-by-using-supertokens\" aria-label=\"add mfa to react fast by using supertokens permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Add MFA to React Fast by using SuperTokens</h2>\n<p>Passwords alone aren’t enough. Credential-stuffing attacks, phishing campaigns, and database breaches mean that even strong passwords end up in the hands of attackers. Multi-factor authentication addresses this by requiring a second verification step, which attackers can’t easily replicate.</p>\n<p>The challenge for React developers: building MFA flows from scratch involves token management, session state, UI routing for factor challenges, and recovery mechanisms. The solution: SuperTokens provides pre-built MFA recipes that handle these complexities, letting you add strong second-factor security with minimal custom code.</p>\n<h2 id=\"what-is-mfa-in-a-react-context\" style=\"position:relative;\"><a href=\"#what-is-mfa-in-a-react-context\" aria-label=\"what is mfa in a react context permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>What Is MFA in a React Context?</h2>\n<p>MFA requires users to prove their identity through multiple independent factors before granting access. After the primary login, users complete a second verification step by using something they have (an authenticator app), something they know (a one-time code), or something they are (biometrics).</p>\n<h3 id=\"how-react-apps-handle-mfa-flows\" style=\"position:relative;\"><a href=\"#how-react-apps-handle-mfa-flows\" aria-label=\"how react apps handle mfa flows permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>How React Apps Handle MFA Flows</h3>\n<p>React applications split MFA responsibility between the frontend and the authentication backend. React controls the user interface: rendering login forms, displaying factor challenges, and routing users through the authentication sequence. The auth SDK manages token storage, session state, and API calls to verification endpoints.</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">User submits credentials\n    ↓\nBackend validates password, returns partial session\n    ↓\nReact receives \"MFA required\" response\n    ↓\nUI routes to factor challenge screen\n    ↓\nUser completes second factor\n    ↓\nBackend validates factor, upgrades session\n    ↓\nUser accesses protected routes</code></pre></div>\n<p>SuperTokens handles this coordination through its React SDK. Pre-built UI components manage factor setup and verification, while hooks let you check whether MFA is complete before rendering protected content. React components send user input to SuperTokens endpoints, and then render the appropriate UI based on the authentication state. Cryptographic operations stay server-side where they belong.</p>\n<h2 id=\"key-mfa-methods-you-can-enable-with-supertokens\" style=\"position:relative;\"><a href=\"#key-mfa-methods-you-can-enable-with-supertokens\" aria-label=\"key mfa methods you can enable with supertokens permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Key MFA Methods You Can Enable with SuperTokens</h2>\n<p>SuperTokens supports three second-factor options, each with distinct trade-offs for security and user experience.</p>\n<p><strong>Time-Based One-Time Passwords (TOTP)</strong></p>\n<p>Users scan a QR code with an authenticator app like Google Authenticator or Authy. The app generates six-digit codes that refresh every 30 seconds. Both the app and your server calculate codes from a shared secret, so verification works offline without network dependencies. TOTP suits technical users who are comfortable managing authenticator apps and TOTP provides strong security without per-verification costs.</p>\n<p><strong>Email/SMS One-Time Passcodes (OTP)</strong></p>\n<p>The server sends a temporary code to the user’s verified email or phone number. There is zero app installation required, making this the lowest-friction option for consumer SaaS products. The trade-off: each verification requires network delivery, and SMS is vulnerable to SIM-swapping attacks. Email OTP offers better security than SMS, while maintaining accessibility for non-technical users.</p>\n<p><strong>Passkeys/WebAuthn</strong></p>\n<p>Hardware-backed authentication by using security keys or device biometrics. The browser handles cryptographic verification with credentials bound to specific origins, providing phishing resistance that TOTP and OTP lack. When a user registers a passkey, their device generates a key pair. The private key never leaves the hardware. SuperTokens supports passkeys through its WebAuthn recipe, though adoption remains early compared to TOTP.</p>\n<p>The method you choose depends on your user base. Enterprise applications with security-conscious users lean toward TOTP or passkeys. Consumer products prioritizing conversion often start with email OTP.</p>\n<h2 id=\"planning-your-mfa-roll-out-critical-questions-to-ask\" style=\"position:relative;\"><a href=\"#planning-your-mfa-roll-out-critical-questions-to-ask\" aria-label=\"planning your mfa roll out critical questions to ask permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Planning Your MFA Roll-Out: Critical Questions to Ask</h2>\n<p>Before writing code, answer these architectural questions. Changing MFA policy after launch affects every user session.</p>\n<p><strong>Mandatory vs. Step-Up MFA</strong></p>\n<p>Should all logins require a second factor, or only high-risk actions? Mandatory MFA provides consistent security, but adds friction to every authentication. Step-up MFA lets users browse freely, then triggers additional verification for sensitive operations like password changes, payment modifications, or admin actions. SuperTokens supports both models through claim validators that check MFA completion on specific routes.</p>\n<p><strong>Recovery Mechanism</strong></p>\n<p>Users will lose access to their second factor. Phones break, authenticator apps get deleted, email accounts change. Plan your recovery path before users need it. Options include backup codes generated at setup, secondary email verification, or administrative override with identity verification. Without a recovery mechanism, locked-out users become support tickets or abandoned accounts.</p>\n<p><strong>Device Remembering</strong></p>\n<p>Requiring MFA on every login from the same device frustrates users. Device trust lets users skip the second factor on recognized browsers for a configured period. The trade-off: a compromised device with remembered trust bypasses MFA entirely. Consider shorter trust periods (7-14 days) for sensitive applications or disabling device trust for admin accounts.</p>\n<p><strong>Scaling and Latency</strong></p>\n<p>MFA verification adds a round-trip to your auth flow. For large user bases, consider where the session state lives. Centralized session stores (Redis, database) enable instant revocation, but add latency. Stateless JWTs reduce database calls, but complicate mid-session revocation. SuperTokens supports both patterns, with built-in token theft detection that works across either architecture.</p>\n<h2 id=\"step-by-step-integration-overview\" style=\"position:relative;\"><a href=\"#step-by-step-integration-overview\" aria-label=\"step by step integration overview permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Step-by-Step Integration Overview</h2>\n<p>This roadmap covers the integration sequence. Full code examples live in the SuperTokens MFA documentation.</p>\n<p><strong>1. Spin Up SuperTokens Core</strong></p>\n<p>Run the core service via Docker or use SuperTokens’ managed offering. The core handles session management, token generation, and factor verification logic.</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"11551548558987390000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"Copied!\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`docker run -p 3567:3567 -d registry.supertokens.io/supertokens/supertokens-postgresql`, `11551548558987390000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                <svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">docker</span> run -p <span class=\"token number\">3567</span>:3567 -d registry.supertokens.io/supertokens/supertokens-postgresql</code></pre></div>\n<p><strong>2. Enable Email-Password and Session Recipes</strong></p>\n<p>Configure your backend SDK with the primary authentication recipe and session management. This establishes the first factor before adding MFA.</p>\n<p><strong>3. Add TOTP or OTP Recipe</strong></p>\n<p>Enable your chosen second factor in the recipe list. Configure requirements: whether MFA is mandatory for all users or triggered conditionally.</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"11973410851822041000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"Copied!\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`import EmailPassword from &quot;supertokens-node/recipe/emailpassword&quot;;\nimport MultiFactorAuth from &quot;supertokens-node/recipe/multifactorauth&quot;;\nimport TOTP from &quot;supertokens-node/recipe/totp&quot;;\nimport Session from &quot;supertokens-node/recipe/session&quot;;\n\nrecipeList: [\n    EmailPassword.init(),\n    TOTP.init(),\n    MultiFactorAuth.init({\n        firstFactors: [&quot;emailpassword&quot;],\n    }),\n    Session.init()\n]`, `11973410851822041000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                <svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">import</span> EmailPassword <span class=\"token keyword\">from</span> <span class=\"token string\">\"supertokens-node/recipe/emailpassword\"</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">import</span> MultiFactorAuth <span class=\"token keyword\">from</span> <span class=\"token string\">\"supertokens-node/recipe/multifactorauth\"</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">import</span> <span class=\"token constant\">TOTP</span> <span class=\"token keyword\">from</span> <span class=\"token string\">\"supertokens-node/recipe/totp\"</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">import</span> Session <span class=\"token keyword\">from</span> <span class=\"token string\">\"supertokens-node/recipe/session\"</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token literal-property property\">recipeList</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>\n    EmailPassword<span class=\"token punctuation\">.</span><span class=\"token function\">init</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n    <span class=\"token constant\">TOTP</span><span class=\"token punctuation\">.</span><span class=\"token function\">init</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n    MultiFactorAuth<span class=\"token punctuation\">.</span><span class=\"token function\">init</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n        <span class=\"token literal-property property\">firstFactors</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">\"emailpassword\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n    Session<span class=\"token punctuation\">.</span><span class=\"token function\">init</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">]</span></code></pre></div>\n<p><strong>4. Wire the Frontend SDK</strong></p>\n<p>Initialize SuperTokens in your React app. The pre-built UI components for login, factor setup, and verification auto-mount under <code class=\"language-text\">/auth</code>. Users see TOTP QR codes and input fields,without custom component work.</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"72236761257520960000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"Copied!\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`import supertokens from &quot;supertokens-auth-react&quot;;\nimport EmailPassword from &quot;supertokens-auth-react/recipe/emailpassword&quot;;\nimport MultiFactorAuth from &quot;supertokens-auth-react/recipe/multifactorauth&quot;;\nimport TOTP from &quot;supertokens-auth-react/recipe/totp&quot;;\nimport Session from &quot;supertokens-auth-react/recipe/session&quot;;\n\nsupertokens.init({\n    appInfo: {\n        appName: &quot;...&quot;,\n        apiDomain: &quot;...&quot;,\n        websiteDomain: &quot;...&quot;,\n    },\n    recipeList: [\n        EmailPassword.init(),\n        TOTP.init(),\n        MultiFactorAuth.init({\n            firstFactors: [&quot;emailpassword&quot;],\n        }),\n        Session.init()\n    ]\n});`, `72236761257520960000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                <svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">import</span> supertokens <span class=\"token keyword\">from</span> <span class=\"token string\">\"supertokens-auth-react\"</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">import</span> EmailPassword <span class=\"token keyword\">from</span> <span class=\"token string\">\"supertokens-auth-react/recipe/emailpassword\"</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">import</span> MultiFactorAuth <span class=\"token keyword\">from</span> <span class=\"token string\">\"supertokens-auth-react/recipe/multifactorauth\"</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">import</span> <span class=\"token constant\">TOTP</span> <span class=\"token keyword\">from</span> <span class=\"token string\">\"supertokens-auth-react/recipe/totp\"</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">import</span> Session <span class=\"token keyword\">from</span> <span class=\"token string\">\"supertokens-auth-react/recipe/session\"</span><span class=\"token punctuation\">;</span>\n\nsupertokens<span class=\"token punctuation\">.</span><span class=\"token function\">init</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n    <span class=\"token literal-property property\">appInfo</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token literal-property property\">appName</span><span class=\"token operator\">:</span> <span class=\"token string\">\"...\"</span><span class=\"token punctuation\">,</span>\n        <span class=\"token literal-property property\">apiDomain</span><span class=\"token operator\">:</span> <span class=\"token string\">\"...\"</span><span class=\"token punctuation\">,</span>\n        <span class=\"token literal-property property\">websiteDomain</span><span class=\"token operator\">:</span> <span class=\"token string\">\"...\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">recipeList</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>\n        EmailPassword<span class=\"token punctuation\">.</span><span class=\"token function\">init</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n        <span class=\"token constant\">TOTP</span><span class=\"token punctuation\">.</span><span class=\"token function\">init</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n        MultiFactorAuth<span class=\"token punctuation\">.</span><span class=\"token function\">init</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n            <span class=\"token literal-property property\">firstFactors</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">\"emailpassword\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n        Session<span class=\"token punctuation\">.</span><span class=\"token function\">init</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">]</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p><strong>5. Protect Routes with SessionAuth</strong></p>\n<p>Wrap protected components with <code class=\"language-text\">SessionAuth</code>. The wrapper checks session validity and MFA completion before rendering children. Incomplete sessions redirect to the appropriate challenge screen.</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"28563820539459520000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"Copied!\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`import { SessionAuth } from &quot;supertokens-auth-react/recipe/session&quot;;\nimport { BrowserRouter, Routes, Route } from &quot;react-router-dom&quot;;\n\nfunction App() {\n    return (\n        <BrowserRouter>\n            <Routes>\n                <Route\n                    path=&quot;/dashboard&quot;\n                    element={\n                        <SessionAuth>\n                            <Dashboard />\n                        </SessionAuth>\n                    }\n                />\n            </Routes>\n        </BrowserRouter>\n    );\n}`, `28563820539459520000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                <svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> SessionAuth <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">\"supertokens-auth-react/recipe/session\"</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> BrowserRouter<span class=\"token punctuation\">,</span> Routes<span class=\"token punctuation\">,</span> Route <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">\"react-router-dom\"</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">App</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n        <span class=\"token operator\">&lt;</span>BrowserRouter<span class=\"token operator\">></span>\n            <span class=\"token operator\">&lt;</span>Routes<span class=\"token operator\">></span>\n                <span class=\"token operator\">&lt;</span>Route\n                    path<span class=\"token operator\">=</span><span class=\"token string\">\"/dashboard\"</span>\n                    element<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>\n                        <span class=\"token operator\">&lt;</span>SessionAuth<span class=\"token operator\">></span>\n                            <span class=\"token operator\">&lt;</span>Dashboard <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n                        <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>SessionAuth<span class=\"token operator\">></span>\n                    <span class=\"token punctuation\">}</span>\n                <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n            <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>Routes<span class=\"token operator\">></span>\n        <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>BrowserRouter<span class=\"token operator\">></span>\n    <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p><strong>6. Test Token Rotation and Theft Detection</strong></p>\n<p>You don’t need to build token rotation or theft detection yourself. <code class=\"language-text\">Session.init()</code> handles both out of the box.</p>\n<p>Here’s the mechanism. SuperTokens issues short-lived access tokens paired with long-lived refresh tokens. Every time the frontend calls the refresh endpoint, the server issues a brand new refresh token and invalidates the previous one. If an attacker steals an old refresh token and tries to use it after the legitimate user has already rotated, SuperTokens flags it as theft and revokes the entire session. Both the attacker and the real user get logged out, forcing re-authentication.</p>\n<p>One detail worth understanding: SuperTokens doesn’t kill the old refresh token the instant it issues a new pair. It waits until the new tokens are actually used by the client. This prevents false lockouts when a refresh response gets dropped by a flaky network. The old token only becomes truly invalid once the new one is confirmed in play.</p>\n<p>To see this working in your app, open your browser DevTools and navigate to the Application tab. Under Cookies, watch the <code class=\"language-text\">sRefreshToken</code> value. Log in, then trigger a refresh (you can let the access token expire naturally or call a protected route). The <code class=\"language-text\">sRefreshToken</code> value changes on every rotation cycle. If you’re running the <a href=\"https://supertokens.com/docs/post-authentication/dashboard/about\" target=\"_blank\" rel=\"nofollow\">SuperTokens Dashboard</a> (<code class=\"language-text\">Dashboard.init()</code> in your recipe list), you can view active sessions per user and watch them get revoked in real time when theft detection triggers.</p>\n<p>The important takeaway: this isn’t something you configure or toggle on. It’s baked into the session layer. If <code class=\"language-text\">Session.init()</code> is in your recipe list, you have rotating refresh tokens and theft detection running from day one.</p>\n<h2 id=\"security-best-practices-for-react-mfa\" style=\"position:relative;\"><a href=\"#security-best-practices-for-react-mfa\" aria-label=\"security best practices for react mfa permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Security Best Practices for React MFA</h2>\n<p>MFA strengthens authentication, but implementation details determine whether that strength holds.</p>\n<p><strong>Rotate Refresh Tokens on Every Use</strong></p>\n<p>SuperTokens issues a new refresh token every time the current one is used. But the old token isn’t invalidated immediately. It stays valid until the client confirms receipt by actually using the new token pair. This prevents false lockouts from dropped network responses. Once the new tokens are in use, the old refresh token is invalidated. If an attacker tries to use that old token after it’s been invalidated, SuperTokens detects the reuse as theft and revokes the entire session, forcing both parties to re-authenticate. This rotation strategy is enabled by default in <code class=\"language-text\">Session.init()</code>.</p>\n<p><strong>Use Secure, HttpOnly Cookies</strong></p>\n<p>Store tokens in cookies by using the <code class=\"language-text\">Secure</code>, <code class=\"language-text\">HttpOnly</code>, and <code class=\"language-text\">SameSite</code> attributes. This prevents JavaScript access (blocking XSS extraction) and ensures transmission only over HTTPS. Avoid localStorage for authentication tokens in browser environments.</p>\n<p><strong>Set Short Access Token TTLs</strong></p>\n<p>Keep access tokens short-lived, ideally 15 minutes or less. Short TTLs limit the damage window if a token leaks. Pair this with silent refresh to maintain user sessions without re-prompting for credentials.</p>\n<p><strong>Log Token Theft Detection Events</strong></p>\n<p>SuperTokens exposes an <code class=\"language-text\">onTokenTheftDetected</code> handler inside <code class=\"language-text\">Session.init()</code> that fires when rotating refresh token reuse is detected. The default behavior revokes the session and sends a <code class=\"language-text\">401</code>. You can hook into this to add logging before that happens.</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"30140599461817330000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"Copied!\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`Session.init({\n    errorHandlers: {\n        onTokenTheftDetected: async (sessionHandle, userId, req, res, userContext) => {\n            // Log the event with whatever context matters to you\n            console.error(&quot;Token theft detected&quot;, {\n                sessionHandle,\n                userId,\n                ip: req.headers[&quot;x-forwarded-for&quot;] || req.connection?.remoteAddress,\n                userAgent: req.headers[&quot;user-agent&quot;],\n                timestamp: new Date().toISOString(),\n            });\n\n            // Revoke the compromised session and respond with 401\n            await Session.revokeSession(sessionHandle);\n            res.statusCode = 401;\n            res.json({ message: &quot;session revoked&quot; });\n        },\n    }\n})`, `30140599461817330000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                <svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">Session<span class=\"token punctuation\">.</span><span class=\"token function\">init</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n    <span class=\"token literal-property property\">errorHandlers</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token function-variable function\">onTokenTheftDetected</span><span class=\"token operator\">:</span> <span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">sessionHandle<span class=\"token punctuation\">,</span> userId<span class=\"token punctuation\">,</span> req<span class=\"token punctuation\">,</span> res<span class=\"token punctuation\">,</span> userContext</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n            <span class=\"token comment\">// Log the event with whatever context matters to you</span>\n            console<span class=\"token punctuation\">.</span><span class=\"token function\">error</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"Token theft detected\"</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span>\n                sessionHandle<span class=\"token punctuation\">,</span>\n                userId<span class=\"token punctuation\">,</span>\n                <span class=\"token literal-property property\">ip</span><span class=\"token operator\">:</span> req<span class=\"token punctuation\">.</span>headers<span class=\"token punctuation\">[</span><span class=\"token string\">\"x-forwarded-for\"</span><span class=\"token punctuation\">]</span> <span class=\"token operator\">||</span> req<span class=\"token punctuation\">.</span>connection<span class=\"token operator\">?.</span>remoteAddress<span class=\"token punctuation\">,</span>\n                <span class=\"token literal-property property\">userAgent</span><span class=\"token operator\">:</span> req<span class=\"token punctuation\">.</span>headers<span class=\"token punctuation\">[</span><span class=\"token string\">\"user-agent\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n                <span class=\"token literal-property property\">timestamp</span><span class=\"token operator\">:</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Date</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">toISOString</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n            <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n            <span class=\"token comment\">// Revoke the compromised session and respond with 401</span>\n            <span class=\"token keyword\">await</span> Session<span class=\"token punctuation\">.</span><span class=\"token function\">revokeSession</span><span class=\"token punctuation\">(</span>sessionHandle<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            res<span class=\"token punctuation\">.</span>statusCode <span class=\"token operator\">=</span> <span class=\"token number\">401</span><span class=\"token punctuation\">;</span>\n            res<span class=\"token punctuation\">.</span><span class=\"token function\">json</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">message</span><span class=\"token operator\">:</span> <span class=\"token string\">\"session revoked\"</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>The handler receives the <code class=\"language-text\">sessionHandle</code> and <code class=\"language-text\">userId</code> directly, so you don’t need to extract them from the request. Replace <code class=\"language-text\">console.error</code> with your logging service of choice. The key point: this runs automatically when theft is detected. You’re not polling or checking manually. SuperTokens calls this handler for you when it sees an invalidated refresh token get replayed.</p>\n<p>SuperTokens also provides <code class=\"language-text\">errorHandlers</code> for other session errors like <code class=\"language-text\">onUnauthorised</code> and <code class=\"language-text\">onTryRefreshToken</code>. Full details in the <a href=\"https://supertokens.com/docs/post-authentication/session-management/advanced-workflows/customize-error-handling\" target=\"_blank\" rel=\"nofollow\">error handling docs</a>.</p>\n<p><strong>Serve All MFA Endpoints over HTTPS</strong></p>\n<p>TOTP secrets, OTP codes, and session tokens must never traverse unencrypted connections. Enforce HTTPS at the infrastructure level and reject plaintext requests. This applies to development environments too, since local testing habits become production configurations.</p>\n<h2 id=\"how-supertokens-simplifies-react-mfa\" style=\"position:relative;\"><a href=\"#how-supertokens-simplifies-react-mfa\" aria-label=\"how supertokens simplifies react mfa permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>How SuperTokens Simplifies React MFA</h2>\n<p>Building MFA from scratch means implementing factor enrollment flows, token management, recovery mechanisms, and session state coordination. SuperTokens handles this infrastructure so you can focus on application logic.</p>\n<p><strong>Drop-In UI Components</strong></p>\n<p>Pre-built screens for signup, factor setup, and verification mount automatically under <code class=\"language-text\">/auth</code>. Users see polished flows for scanning TOTP QR codes, entering verification codes, and managing backup options. Custom styling is supported when defaults don’t match your design system.</p>\n<p><strong>Flexible Policy Engine</strong></p>\n<p>Claim validators let you require MFA globally or on specific routes. Protect admin panels with mandatory second factors while letting standard users browse freely. Policies evaluate at request time, so changes apply without redeployment.</p>\n<p><strong>Built-In Token Theft Detection</strong></p>\n<p>When refresh tokens rotate, SuperTokens tracks expected values. If an attacker uses a stolen token while the legitimate user continues their session, the system detects the conflict and revokes all sessions for that user. No custom implementation required.</p>\n<p><strong>Pluggable Factors</strong></p>\n<p>Switching from TOTP to email OTP requires a configuration change, not a rewrite. Add multiple factor options and let users choose their preference. The underlying session management remains consistent regardless of which factor verifies the user.</p>\n<p><strong>Open Source and Self-Hostable</strong></p>\n<p>Run SuperTokens Core on your infrastructure to meet data residency requirements or compliance mandates. The open-source model means you can audit the code handling your authentication logic and avoid vendor lock-in.</p>\n<h2 id=\"additional-technical-considerations\" style=\"position:relative;\"><a href=\"#additional-technical-considerations\" aria-label=\"additional technical considerations permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Additional Technical Considerations</h2>\n<p>MFA integration touches more than just login screens. Consider how your architecture affects implementation.</p>\n<p><strong>SSR and Next.js</strong></p>\n<p>Server-side rendering (SSR) requires session verification on both the client and server. The SuperTokens Next.js SDK handles this by checking sessions during server rendering and hydrating state on the client. Without proper SSR support, users see authentication flickers or incorrect UI states on initial page loads. Middleware integration lets you protect routes at the edge before rendering begins.</p>\n<p><strong>Microservices Architecture</strong></p>\n<p>In service-mesh deployments, each service needs to validate tokens without calling SuperTokens Core on every request. JWTs enable local validation by using public keys, while Core remains the authority for revocation. When a session is revoked, services continue accepting the token until TTL expiration. Balance TTL length against your revocation latency requirements.</p>\n<p><strong>Analytics and A/B Testing</strong></p>\n<p>Track MFA adoption and drop-off rates through recipe hooks. SuperTokens exposes events for factor setup initiation, completion, and failure. Pipe these to your analytics system to measure conversion impact. Hook implementations receive session context without exposing TOTP secrets or verification codes, keeping sensitive data out of analytics pipelines.</p>\n<h2 id=\"common-pitfalls-and-how-to-avoid-them\" style=\"position:relative;\"><a href=\"#common-pitfalls-and-how-to-avoid-them\" aria-label=\"common pitfalls and how to avoid them permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Common Pitfalls and How to Avoid Them</h2>\n<p>These mistakes undermine MFA security even when the rest of your implementation is solid.</p>\n<p><strong>Storing TOTP Secrets in Plaintext</strong></p>\n<p>TOTP secrets are equivalent to passwords. If an attacker accesses your database, plaintext secrets let them generate valid codes for any user. SuperTokens encrypts TOTP secrets at rest. If you’re managing secrets manually, encrypt them with a key stored outside the database.</p>\n<p><strong>Skipping CSRF Protection on OTP Endpoints</strong></p>\n<p>OTP verification endpoints work by accepting a code and upgrading session privileges. Without CSRF protection, an attacker who knows a user’s OTP (via social engineering or interception) can submit it from a malicious site by using the user’s existing session cookie. SuperTokens includes anti-CSRF middleware by default. Don’t disable it to “simplify” development.</p>\n<p><strong>Long-Lived JWTs</strong></p>\n<p>Extended token lifetimes feel convenient but defeat MFA’s purpose. If an attacker captures a JWT valid for 24 hours, they have 24 hours of access, regardless of MFA. The user can’t revoke the session until expiration. Keep access tokens short (15 minutes or less) and use refresh token rotation. The minor latency cost of frequent refreshes is worth the security gain.</p>\n<h2 id=\"future-proofing-your-mfa-stack\" style=\"position:relative;\"><a href=\"#future-proofing-your-mfa-stack\" aria-label=\"future proofing your mfa stack permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Future-Proofing Your MFA Stack</h2>\n<p>Authentication standards evolve. Building on extensible infrastructure lets you adopt new factors without rewriting your auth system.</p>\n<p><strong>Passkeys and Device Public Keys</strong></p>\n<p>WebAuthn adoption is accelerating as browsers and operating systems add native support. Passkeys eliminate shared secrets entirely: users authenticate with device biometrics or security keys, and private keys never leave the hardware. SuperTokens supports WebAuthn integrations, positioning your app to offer passkeys as user adoption grows. Start with TOTP or OTP today, add passkeys as a secondary option for early adopters.</p>\n<p><strong>Risk-Based Adaptive MFA</strong></p>\n<p>Static MFA policies treat every login identically. Adaptive approaches analyze signals like user-agent changes, IP geolocation shifts, and login time patterns to adjust factor requirements dynamically. A user logging in from their usual device and location might skip MFA, while the same user connecting from a new country triggers additional verification. SuperTokens’ claim validators provide the foundation for implementing risk scoring logic.</p>\n<p><strong>Zero-Knowledge Proof Factors</strong></p>\n<p>Emerging standards explore verification without revealing underlying data. A user could prove they possess a valid credential without transmitting the credential itself. These protocols remain experimental, but privacy regulations may drive adoption. Choosing an open-source, extensible auth platform keeps your options open as standards evolve.</p>\n<h2 id=\"conclusion-ship-mfa-the-smart-way\" style=\"position:relative;\"><a href=\"#conclusion-ship-mfa-the-smart-way\" aria-label=\"conclusion ship mfa the smart way permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Conclusion: Ship MFA the Smart Way</h2>\n<p>Password-only authentication is a liability. Credential breaches happen constantly, and users reuse passwords across services. MFA provides meaningful protection against account takeover, but only if you implement it correctly.</p>\n<p>Building MFA from scratch means handling TOTP secret encryption, token rotation, theft detection, recovery flows, and session state management. Each component introduces opportunities for security gaps. SuperTokens provides tested implementations of these pieces, letting you add MFA to React applications without rebuilding authentication infrastructure.</p>\n<p>Start with the factor that fits your users: TOTP for technical audiences, email OTP for consumer products, passkeys for security-forward applications. Plan your recovery mechanism before launch. Keep tokens short-lived and rotate them on every refresh.</p>\n<p>SuperTokens’ documentation includes complete integration guides for React, Next.js, and backend frameworks. If you’ve followed along with this overview, you have the conceptual foundation. The implementation is straightforward from here.</p>","frontmatter":{"date":"March 09, 2026","title":"Add MFA to React Fast with SuperTokens","cover":"add_mfa_to_react.png","author":"Maurice Saldivar","description":"Secure your React app with multi-factor authentication in minutes. Learn MFA options, setup steps, and best practices using SuperTokens."},"fields":{"slug":"/mfa-react/"}},"site":{"siteMetadata":{"title":"SuperTokens Blog"}}},"pageContext":{"id":"17da54ba-83b0-5d71-be48-3ae4482a4eb5","fields__slug":"/mfa-react/","__params":{"fields__slug":"mfa-react"}}},
    "staticQueryHashes": []}