{
    "componentChunkName": "component---src-pages-blog-markdown-remark-fields-slug-js",
    "path": "/blog/magiclinks",
    "result": {"data":{"markdownRemark":{"html":"<h2 id=\"table-of-contents\" style=\"position:relative;\"><a href=\"#table-of-contents\" aria-label=\"table of contents 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>Table of Contents</h2>\n<ul>\n<li><a href=\"#what-are-magic-links-and-why-they-matter\">What Are Magic Links and Why They Matter</a></li>\n<li><a href=\"#what-is-a-magic-link\">What Is a Magic Link?</a>\n<ul>\n<li><a href=\"#definition\">Definition</a></li>\n<li><a href=\"#how-it-works\">How It Works</a></li>\n<li><a href=\"#use-cases\">Use Cases</a></li>\n</ul>\n</li>\n<li><a href=\"#how-do-magic-links-improve-authentication\">How Do Magic Links Improve Authentication?</a>\n<ul>\n<li><a href=\"#frictionless-ux\">Frictionless UX</a></li>\n<li><a href=\"#reduced-attack-surface\">Reduced Attack Surface</a></li>\n<li><a href=\"#lower-support-load\">Lower Support Load</a></li>\n</ul>\n</li>\n<li><a href=\"#technical-implementation-of-magic-links\">Technical Implementation of Magic Links</a>\n<ul>\n<li><a href=\"#step-by-step-backend-workflow\">Step-by-Step Backend Workflow</a></li>\n<li><a href=\"#frontend-best-practices\">Frontend Best Practices</a></li>\n<li><a href=\"#security-recommendations\">Security Recommendations</a></li>\n</ul>\n</li>\n<li><a href=\"#magic-links-vs-other-passwordless-methods\">Magic Links vs Other Passwordless Methods</a>\n<ul>\n<li><a href=\"#comparison-table\">Comparison Table</a></li>\n<li><a href=\"#detailed-method-analysis\">Detailed Method Analysis</a></li>\n<li><a href=\"#when-to-use-magic-links-over-others\">When to Use Magic Links Over Others</a></li>\n</ul>\n</li>\n<li><a href=\"#how-supertokens-simplifies-magic-link-integration\">How SuperTokens Simplifies Magic Link Integration</a>\n<ul>\n<li><a href=\"#built-in-passwordless-recipe\">Built-In Passwordless Recipe</a></li>\n<li><a href=\"#customizable-flows\">Customizable Flows</a></li>\n<li><a href=\"#security-and-scalability\">Security and Scalability</a></li>\n<li><a href=\"#documentation-reference\">Documentation Reference</a></li>\n</ul>\n</li>\n<li><a href=\"#common-implementation-challenges\">Common Implementation Challenges</a>\n<ul>\n<li><a href=\"#email-deliverability\">Email Deliverability</a></li>\n<li><a href=\"#expired-links\">Expired Links</a></li>\n<li><a href=\"#device-recognition\">Device Recognition</a></li>\n</ul>\n</li>\n<li><a href=\"#best-practices-for-magic-link-authentication\">Best Practices for Magic Link Authentication</a>\n<ul>\n<li><a href=\"#short-expiration-window\">Short Expiration Window</a></li>\n<li><a href=\"#one-time-usage\">One-Time Usage</a></li>\n<li><a href=\"#secure-token-storage\">Secure Token Storage</a></li>\n<li><a href=\"#optional-2fa-layer\">Optional 2FA Layer</a></li>\n<li><a href=\"#analytics-and-logging\">Analytics and Logging</a></li>\n</ul>\n</li>\n<li><a href=\"#who-uses-magic-links-successfully\">Who Uses Magic Links Successfully?</a>\n<ul>\n<li><a href=\"#examples\">Examples</a></li>\n<li><a href=\"#why-these-companies-use-them\">Why These Companies Use Them</a></li>\n</ul>\n</li>\n<li><a href=\"#is-a-magic-link-strategy-right-for-you\">Is a Magic Link Strategy Right for You?</a>\n<ul>\n<li><a href=\"#great-fit-if\">Great Fit If:</a></li>\n<li><a href=\"#not-ideal-if\">Not Ideal If:</a></li>\n</ul>\n</li>\n<li><a href=\"#conclusion\">Conclusion</a></li>\n</ul>\n<h2 id=\"what-are-magic-links-and-why-they-matter\" style=\"position:relative;\"><a href=\"#what-are-magic-links-and-why-they-matter\" aria-label=\"what are magic links and why they matter 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 Are Magic Links and Why They Matter</h2>\n<p>A comprehensive guide to understanding, implementing, and optimizing magic link authentication in modern web applications.</p>\n<h2 id=\"what-is-a-magic-link\" style=\"position:relative;\"><a href=\"#what-is-a-magic-link\" aria-label=\"what is a magic link 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 a Magic Link?</h2>\n<p>A magic link is a one-time use URL sent to a user’s email to authenticate them without requiring a password. This URL contains a cryptographically secure token that uniquely identifies an authentication request and grants access when clicked. The link typically follows a structure like <code class=\"language-text\">https://app.example.com/auth/verify?token=a4f8c2e9b7d3f6e2</code> where the token serves as a temporary credential.</p>\n<p>Magic links shift the authentication factor from something you know (a password) to something you have (access to an email account). This fundamental change eliminates entire categories of security vulnerabilities while simplifying the user experience.</p>\n<h3 id=\"how-it-works\" style=\"position:relative;\"><a href=\"#how-it-works\" aria-label=\"how it works 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 It Works</h3>\n<p>The magic link authentication flow consists of five distinct steps:</p>\n<ol>\n<li><strong>User Initiates Login</strong>: The user enters their email address on the login page</li>\n<li><strong>Token Generation</strong>: The server generates a cryptographically random token and stores it with metadata including timestamp, user identifier, and expiration time</li>\n<li><strong>Email Delivery</strong>: The system sends an email containing the unique authentication URL to the user’s registered address</li>\n<li><strong>Link Activation</strong>: The user clicks the link, sending the token back to the server</li>\n<li><strong>Verification and Session Creation</strong>: The server validates the token, confirms it hasn’t expired or been used, then creates an authenticated session</li>\n</ol>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"22650148850849948000\"\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(`// Server-side token generation example\nconst crypto = require('crypto');\n\nasync function generateMagicLink(email) {\n  // Generate token and hash\n  const token = crypto.randomBytes(32).toString('hex');\n  const tokenHash = crypto.createHash('sha256').update(token).digest('hex');\n  \n  // Store token with metadata\n  await storeToken({\n    token: hashToken(token),\n    email: email,\n    createdAt: Date.now(),\n    expiresAt: Date.now() + (15 * 60 * 1000),\n    used: false\n  });\n  \n  // Create magic link URL\n  const magicLink = \\`\\${process.env.APP_URL}/auth/verify?token=\\${token}\\`;\n  \n  return magicLink;\n}`, `22650148850849948000`)\"\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 comment\">// Server-side token generation example</span>\n<span class=\"token keyword\">const</span> crypto <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'crypto'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">async</span> <span class=\"token keyword\">function</span> <span class=\"token function\">generateMagicLink</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">email</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token comment\">// Generate token and hash</span>\n  <span class=\"token keyword\">const</span> token <span class=\"token operator\">=</span> crypto<span class=\"token punctuation\">.</span><span class=\"token function\">randomBytes</span><span class=\"token punctuation\">(</span><span class=\"token number\">32</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">toString</span><span class=\"token punctuation\">(</span><span class=\"token string\">'hex'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">const</span> tokenHash <span class=\"token operator\">=</span> crypto<span class=\"token punctuation\">.</span><span class=\"token function\">createHash</span><span class=\"token punctuation\">(</span><span class=\"token string\">'sha256'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">update</span><span class=\"token punctuation\">(</span>token<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">digest</span><span class=\"token punctuation\">(</span><span class=\"token string\">'hex'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token comment\">// Store token with metadata</span>\n  <span class=\"token keyword\">await</span> <span class=\"token function\">storeToken</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n    <span class=\"token literal-property property\">token</span><span class=\"token operator\">:</span> <span class=\"token function\">hashToken</span><span class=\"token punctuation\">(</span>token<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">email</span><span class=\"token operator\">:</span> email<span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">createdAt</span><span class=\"token operator\">:</span> Date<span class=\"token punctuation\">.</span><span class=\"token function\">now</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">expiresAt</span><span class=\"token operator\">:</span> Date<span class=\"token punctuation\">.</span><span class=\"token function\">now</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">+</span> <span class=\"token punctuation\">(</span><span class=\"token number\">15</span> <span class=\"token operator\">*</span> <span class=\"token number\">60</span> <span class=\"token operator\">*</span> <span class=\"token number\">1000</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">used</span><span class=\"token operator\">:</span> <span class=\"token boolean\">false</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token comment\">// Create magic link URL</span>\n  <span class=\"token keyword\">const</span> magicLink <span class=\"token operator\">=</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>process<span class=\"token punctuation\">.</span>env<span class=\"token punctuation\">.</span><span class=\"token constant\">APP_URL</span><span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">/auth/verify?token=</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>token<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">return</span> magicLink<span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>The backend token match happens when the user clicks the link. The server receives the token, looks it up in the database, validates its properties, and either grants access or rejects the authentication attempt based on the validation results.</p>\n<p>Token expiration serves as a critical security control. Most implementations expire tokens after 15 to 30 minutes or immediately after first use. This limited validity window reduces the risk of token interception or unauthorized access if an email account is compromised later.</p>\n<h3 id=\"use-cases\" style=\"position:relative;\"><a href=\"#use-cases\" aria-label=\"use cases 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>Use Cases</h3>\n<p>Magic links excel in specific authentication scenarios where traditional passwords create unnecessary friction or security risks.</p>\n<p><strong>Passwordless Logins</strong></p>\n<p>Modern applications increasingly adopt magic links as their primary authentication method. Medium, Slack (for guest users), and Notion demonstrate successful passwordless implementations. These platforms recognized that infrequent users often forget passwords, leading to abandoned sessions and support tickets. Magic links eliminate this friction entirely.</p>\n<p>For applications with sporadic usage patterns, magic links provide superior user experience. A user returning after months doesn’t need to remember or reset a password. They simply enter their email and click the link to regain access.</p>\n<p><strong>Account Recovery</strong></p>\n<p>Traditional password reset flows already resemble magic links: users receive an email with a temporary link to set a new password. Magic links streamline this by eliminating the password entirely. Instead of “reset your password,” the flow becomes “sign in with email.”</p>\n<p>This approach particularly benefits applications migrating from password-based authentication. Users familiar with password reset emails naturally understand magic link authentication, reducing the learning curve during transition.</p>\n<p><strong>Low-Friction Sign-ups</strong></p>\n<p>Conversion optimization research consistently shows that each additional form field reduces completion rates. Magic links enable single field registration: users enter only their email address to create an account and access the application.</p>\n<p>Ecommerce platforms use magic links for guest checkout flows. Customers purchase without creating passwords, reducing cart abandonment while still maintaining order history and user tracking.</p>\n<p>Enterprise applications leverage magic links for temporary access. Contractors, auditors, or short term collaborators receive magic links for time limited access without cluttering the organization’s identity management system with rarely used accounts.</p>\n<p>The asynchronous nature of email based authentication also enables interesting workflows. Document sharing platforms send magic links that simultaneously create accounts and grant document access. This pattern reduces sharing friction while maintaining security and audit trails.</p>\n<h2 id=\"how-do-magic-links-improve-authentication\" style=\"position:relative;\"><a href=\"#how-do-magic-links-improve-authentication\" aria-label=\"how do magic links improve authentication 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 Do Magic Links Improve Authentication?</h2>\n<h3 id=\"frictionless-ux\" style=\"position:relative;\"><a href=\"#frictionless-ux\" aria-label=\"frictionless ux 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>Frictionless UX</h3>\n<p>Password-based authentication creates cognitive load that directly impacts user engagement and conversion metrics. Users maintain an average of 100 passwords across personal and professional accounts, according to <a href=\"https://nordpass.com/blog/how-many-passwords-does-average-person-have/\" target=\"_blank\" rel=\"nofollow\">NordPass’s 2024 study</a>. This password proliferation leads to predictable behaviors: password reuse, weak passwords, and frequent resets.</p>\n<p>Magic links eliminate this cognitive burden entirely. The authentication process requires only email access, something users already manage as part of their digital routine. This simplification yields measurable improvements in user behavior and business metrics.</p>\n<p><strong>Conversion Rate Impact</strong></p>\n<p>Substack’s implementation of magic links increased newsletter subscription conversions by 28% compared to traditional password registration. The simplified flow removed the friction point where users abandon registration when faced with password creation requirements.</p>\n<p><strong>Mobile Experience Benefits</strong></p>\n<p>Password entry on mobile devices remains particularly problematic. Small keyboards, auto-correct interference, and special character accessibility create frustration. Magic links bypass these issues entirely. Users tap their email app notification and authenticate instantly.</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"22033607462674110000\"\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(`// Mobile-optimized magic link flow\nasync function sendMagicLink(email, userAgent) {\n  const isMobile = /iPhone|iPad|iPod|Android/i.test(userAgent);\n  \n  const magicLink = await generateMagicLink(email);\n  \n  // Customize email content for mobile users\n  const emailTemplate = isMobile ? \n    getMobileEmailTemplate(magicLink) : \n    getDesktopEmailTemplate(magicLink);\n  \n  await sendEmail({\n    to: email,\n    subject: 'Your login link',\n    html: emailTemplate,\n    // Deep link for mobile apps\n    headers: isMobile ? {\n      'X-Universal-Link': magicLink\n    } : {}\n  });\n}`, `22033607462674110000`)\"\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 comment\">// Mobile-optimized magic link flow</span>\n<span class=\"token keyword\">async</span> <span class=\"token keyword\">function</span> <span class=\"token function\">sendMagicLink</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">email<span class=\"token punctuation\">,</span> userAgent</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> isMobile <span class=\"token operator\">=</span> <span class=\"token regex\"><span class=\"token regex-delimiter\">/</span><span class=\"token regex-source language-regex\">iPhone|iPad|iPod|Android</span><span class=\"token regex-delimiter\">/</span><span class=\"token regex-flags\">i</span></span><span class=\"token punctuation\">.</span><span class=\"token function\">test</span><span class=\"token punctuation\">(</span>userAgent<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">const</span> magicLink <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> <span class=\"token function\">generateMagicLink</span><span class=\"token punctuation\">(</span>email<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token comment\">// Customize email content for mobile users</span>\n  <span class=\"token keyword\">const</span> emailTemplate <span class=\"token operator\">=</span> isMobile <span class=\"token operator\">?</span> \n    <span class=\"token function\">getMobileEmailTemplate</span><span class=\"token punctuation\">(</span>magicLink<span class=\"token punctuation\">)</span> <span class=\"token operator\">:</span> \n    <span class=\"token function\">getDesktopEmailTemplate</span><span class=\"token punctuation\">(</span>magicLink<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">await</span> <span class=\"token function\">sendEmail</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n    <span class=\"token literal-property property\">to</span><span class=\"token operator\">:</span> email<span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">subject</span><span class=\"token operator\">:</span> <span class=\"token string\">'Your login link'</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">html</span><span class=\"token operator\">:</span> emailTemplate<span class=\"token punctuation\">,</span>\n    <span class=\"token comment\">// Deep link for mobile apps</span>\n    <span class=\"token literal-property property\">headers</span><span class=\"token operator\">:</span> isMobile <span class=\"token operator\">?</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token string-property property\">'X-Universal-Link'</span><span class=\"token operator\">:</span> magicLink\n    <span class=\"token punctuation\">}</span> <span class=\"token operator\">:</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<span class=\"token punctuation\">}</span></code></pre></div>\n<p><strong>Accessibility Advantages</strong></p>\n<p>Magic links improve authentication accessibility for users with disabilities. Password managers often conflict with screen readers, and complex password requirements challenge users with cognitive impairments. Email based authentication leverages familiar email client interfaces that users have already configured for their accessibility needs.</p>\n<h3 id=\"reduced-attack-surface\" style=\"position:relative;\"><a href=\"#reduced-attack-surface\" aria-label=\"reduced attack surface 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>Reduced Attack Surface</h3>\n<p>Traditional password authentication exposes multiple attack vectors that magic links inherently resist or eliminate.</p>\n<p><strong>Phishing Resistance</strong></p>\n<p>While magic links don’t provide complete phishing immunity, they significantly reduce phishing effectiveness. Traditional phishing attacks harvest passwords that remain valid until changed. Magic links expire within minutes and work only once, limiting the window for exploitation.</p>\n<p>Even if users click phishing emails mimicking magic link requests, attackers cannot capture reusable credentials. The token sent to a phishing site becomes worthless after expiration or first use. This temporal limitation fundamentally changes the economics of phishing attacks.</p>\n<p><strong>Credential Stuffing Immunity</strong></p>\n<p>The <a href=\"https://qz.com/1329961/hackers-account-for-90-of-login-attempts-at-online-retailers\" target=\"_blank\" rel=\"nofollow\">2023 Shape Security report</a> identified credential stuffing as being responsible for 90% of login attempts on retail websites. Attackers use automated tools to test stolen username/password combinations across multiple services, exploiting password reuse.</p>\n<p>Magic links eliminate this attack vector completely. Without passwords to steal or reuse, credential stuffing becomes impossible. Each authentication requires a fresh token delivered to the legitimate email account, blocking automated attack tools.</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"26973381852206834000\"\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(`# Traditional auth\ndef traditional_login(username, password):\n    # Attackers can repeatedly attempt different passwords\n    user = get_user(username)\n    if verify_password(password, user.password_hash):\n        return create_session(user)\n    return None\n\n# Magic link auth \ndef magic_link_login(token):\n    # Each token works exactly once\n    stored_token = get_unused_token(token)\n    if not stored_token:\n        return None\n    \n    if stored_token.expires_at < datetime.now():\n        return None\n    \n    # Mark as used immediately\n    mark_token_used(stored_token.id)\n    return create_session(stored_token.user)`, `26973381852206834000`)\"\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=\"python\"><pre class=\"language-python\"><code class=\"language-python\"><span class=\"token comment\"># Traditional auth</span>\n<span class=\"token keyword\">def</span> <span class=\"token function\">traditional_login</span><span class=\"token punctuation\">(</span>username<span class=\"token punctuation\">,</span> password<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    <span class=\"token comment\"># Attackers can repeatedly attempt different passwords</span>\n    user <span class=\"token operator\">=</span> get_user<span class=\"token punctuation\">(</span>username<span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">if</span> verify_password<span class=\"token punctuation\">(</span>password<span class=\"token punctuation\">,</span> user<span class=\"token punctuation\">.</span>password_hash<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n        <span class=\"token keyword\">return</span> create_session<span class=\"token punctuation\">(</span>user<span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">return</span> <span class=\"token boolean\">None</span>\n\n<span class=\"token comment\"># Magic link auth </span>\n<span class=\"token keyword\">def</span> <span class=\"token function\">magic_link_login</span><span class=\"token punctuation\">(</span>token<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    <span class=\"token comment\"># Each token works exactly once</span>\n    stored_token <span class=\"token operator\">=</span> get_unused_token<span class=\"token punctuation\">(</span>token<span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">if</span> <span class=\"token keyword\">not</span> stored_token<span class=\"token punctuation\">:</span>\n        <span class=\"token keyword\">return</span> <span class=\"token boolean\">None</span>\n    \n    <span class=\"token keyword\">if</span> stored_token<span class=\"token punctuation\">.</span>expires_at <span class=\"token operator\">&lt;</span> datetime<span class=\"token punctuation\">.</span>now<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 boolean\">None</span>\n    \n    <span class=\"token comment\"># Mark as used immediately</span>\n    mark_token_used<span class=\"token punctuation\">(</span>stored_token<span class=\"token punctuation\">.</span><span class=\"token builtin\">id</span><span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">return</span> create_session<span class=\"token punctuation\">(</span>stored_token<span class=\"token punctuation\">.</span>user<span class=\"token punctuation\">)</span></code></pre></div>\n<p><strong>Brute Force Prevention</strong></p>\n<p>Password systems require complex rate limiting and account lockout mechanisms to prevent brute force attacks. Attackers attempt thousands of password combinations, exploiting weak or common passwords.</p>\n<p>Magic links inherently resist brute force through cryptographic token strength. A properly generated 256-bit token has 2^256 possible values, making brute force statistically impossible within the token’s lifetime. The combination of high entropy and short expiration creates an impenetrable authentication barrier.</p>\n<p>Additionally, rate limiting becomes simpler. Systems can restrict email sending frequency without complex IP tracking or CAPTCHA systems that frustrate legitimate users.</p>\n<h3 id=\"lower-support-load\" style=\"position:relative;\"><a href=\"#lower-support-load\" aria-label=\"lower support load 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>Lower Support Load</h3>\n<p>Password related issues dominate IT support workloads across organizations of all sizes. <a href=\"https://specopssoft.com/blog/save-money-self-service-password-resets/\" target=\"_blank\" rel=\"nofollow\">Gartner research</a> indicates that password resets account for 40% of help desk call volume, with each reset costing organizations between $20 and $50 in support resources.</p>\n<p><strong>Eliminating Password Reset Tickets</strong></p>\n<p>Magic links remove the primary source of authentication support requests. Users cannot forget passwords that don’t exist. This elimination of password reset tickets provides immediate operational benefits.</p>\n<p><strong>Simplified Troubleshooting</strong></p>\n<p>When authentication issues arise with magic links, troubleshooting follows a predictable pattern: email delivery problems. Support teams need expertise in only one area rather than managing password policies, complexity requirements, expiration rules, and account lockout procedures.</p>\n<p>Common magic link support issues and resolutions:</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"19805768870242947000\"\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(`// Automated troubleshooting for magic link issues\nconst troubleshootMagicLink = {\n  emailNotReceived: {\n    causes: ['Spam folder', 'Email delays', 'Incorrect address'],\n    solutions: [\n      'Check spam/junk folder',\n      'Wait 5 minutes for delivery',\n      'Verify email address',\n      'Resend link'\n    ]\n  },\n  \n  linkExpired: {\n    causes: ['Token timeout', 'Already used'],\n    solutions: ['Request new link']\n  },\n  \n  linkNotWorking: {\n    causes: ['Email client modification', 'Security software'],\n    solutions: [\n      'Copy and paste full link',\n      'Try different browser',\n      'Disable email link scanning'\n    ]\n  }\n};`, `19805768870242947000`)\"\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 comment\">// Automated troubleshooting for magic link issues</span>\n<span class=\"token keyword\">const</span> troubleshootMagicLink <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token literal-property property\">emailNotReceived</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token literal-property property\">causes</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">'Spam folder'</span><span class=\"token punctuation\">,</span> <span class=\"token string\">'Email delays'</span><span class=\"token punctuation\">,</span> <span class=\"token string\">'Incorrect address'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">solutions</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>\n      <span class=\"token string\">'Check spam/junk folder'</span><span class=\"token punctuation\">,</span>\n      <span class=\"token string\">'Wait 5 minutes for delivery'</span><span class=\"token punctuation\">,</span>\n      <span class=\"token string\">'Verify email address'</span><span class=\"token punctuation\">,</span>\n      <span class=\"token string\">'Resend link'</span>\n    <span class=\"token punctuation\">]</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n  \n  <span class=\"token literal-property property\">linkExpired</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token literal-property property\">causes</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">'Token timeout'</span><span class=\"token punctuation\">,</span> <span class=\"token string\">'Already used'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">solutions</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">'Request new link'</span><span class=\"token punctuation\">]</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n  \n  <span class=\"token literal-property property\">linkNotWorking</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token literal-property property\">causes</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">'Email client modification'</span><span class=\"token punctuation\">,</span> <span class=\"token string\">'Security software'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">solutions</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>\n      <span class=\"token string\">'Copy and paste full link'</span><span class=\"token punctuation\">,</span>\n      <span class=\"token string\">'Try different browser'</span><span class=\"token punctuation\">,</span>\n      <span class=\"token string\">'Disable email link scanning'</span>\n    <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><strong>Reduced Security Training Requirements</strong></p>\n<p>Organizations spend considerable resources training employees on password security: complexity requirements, rotation schedules, and phishing recognition. Magic links simplify security training to a single principle: protect your email account.</p>\n<p>This focused security message proves more effective than complex password policies. Users understand email security from personal experience, making training more relatable and actionable. The cumulative effect of these improvements extends beyond direct cost savings. IT teams freed from password support can focus on strategic initiatives. Users spend less time on authentication issues and more time on productive work. The entire organization benefits from reduced authentication friction and improved security posture.</p>\n<h2 id=\"technical-implementation-of-magic-links\" style=\"position:relative;\"><a href=\"#technical-implementation-of-magic-links\" aria-label=\"technical implementation of magic links 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>Technical Implementation of Magic Links</h2>\n<h3 id=\"step-by-step-backend-workflow\" style=\"position:relative;\"><a href=\"#step-by-step-backend-workflow\" aria-label=\"step by step backend workflow 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 Backend Workflow</h3>\n<p>Building a production-ready magic link system requires careful attention to security, reliability, and user experience. The implementation involves four core operations that must work together seamlessly.</p>\n<p><strong>Capture Email Input and Generate a Time-Limited Token</strong></p>\n<p>The authentication flow begins when users submit their email address. The backend must validate the email format, check user existence, and generate a cryptographically secure token.</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"98907560600965510000\"\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(`const crypto = require('crypto');\nconst { z } = require('zod');\n\nconst emailSchema = z.string().email().toLowerCase();\n\nasync function initiateMagicLink(email) {\n  try {\n    const validatedEmail = emailSchema.parse(email);\n  } catch (error) {\n    throw new ValidationError('Invalid email format');\n  }\n  \n  // Check if user exists (create if needed for new signups)\n  const user = await getUserByEmail(validatedEmail) || \n               await createUser(validatedEmail);\n  \n  const token = crypto.randomBytes(32).toString('base64url');\n  \n  const tokenData = {\n    token: token,\n    userId: user.id,\n    email: validatedEmail,\n    createdAt: new Date(),\n    expiresAt: new Date(Date.now() + 15 * 60 * 1000),\n    used: false,\n    ipAddress: request.ip,\n    userAgent: request.headers['user-agent']\n  };\n  \n  return { token, tokenData, user };\n}`, `98907560600965510000`)\"\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\">const</span> crypto <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'crypto'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> z <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'zod'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">const</span> emailSchema <span class=\"token operator\">=</span> z<span class=\"token punctuation\">.</span><span class=\"token function\">string</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">email</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">toLowerCase</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">async</span> <span class=\"token keyword\">function</span> <span class=\"token function\">initiateMagicLink</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">email</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">try</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">const</span> validatedEmail <span class=\"token operator\">=</span> emailSchema<span class=\"token punctuation\">.</span><span class=\"token function\">parse</span><span class=\"token punctuation\">(</span>email<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span> <span class=\"token keyword\">catch</span> <span class=\"token punctuation\">(</span>error<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">throw</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">ValidationError</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Invalid email format'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n  \n  <span class=\"token comment\">// Check if user exists (create if needed for new signups)</span>\n  <span class=\"token keyword\">const</span> user <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> <span class=\"token function\">getUserByEmail</span><span class=\"token punctuation\">(</span>validatedEmail<span class=\"token punctuation\">)</span> <span class=\"token operator\">||</span> \n               <span class=\"token keyword\">await</span> <span class=\"token function\">createUser</span><span class=\"token punctuation\">(</span>validatedEmail<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">const</span> token <span class=\"token operator\">=</span> crypto<span class=\"token punctuation\">.</span><span class=\"token function\">randomBytes</span><span class=\"token punctuation\">(</span><span class=\"token number\">32</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">toString</span><span class=\"token punctuation\">(</span><span class=\"token string\">'base64url'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">const</span> tokenData <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token literal-property property\">token</span><span class=\"token operator\">:</span> token<span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">userId</span><span class=\"token operator\">:</span> user<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">email</span><span class=\"token operator\">:</span> validatedEmail<span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">createdAt</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>\n    <span class=\"token literal-property property\">expiresAt</span><span class=\"token operator\">:</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Date</span><span class=\"token punctuation\">(</span>Date<span class=\"token punctuation\">.</span><span class=\"token function\">now</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">+</span> <span class=\"token number\">15</span> <span class=\"token operator\">*</span> <span class=\"token number\">60</span> <span class=\"token operator\">*</span> <span class=\"token number\">1000</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">used</span><span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">ipAddress</span><span class=\"token operator\">:</span> request<span class=\"token punctuation\">.</span>ip<span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">userAgent</span><span class=\"token operator\">:</span> request<span class=\"token punctuation\">.</span>headers<span class=\"token punctuation\">[</span><span class=\"token string\">'user-agent'</span><span class=\"token punctuation\">]</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span> token<span class=\"token punctuation\">,</span> tokenData<span class=\"token punctuation\">,</span> user <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Token generation must use cryptographically secure random number generators. Node.js’s <code class=\"language-text\">crypto.randomBytes()</code> or Python’s <code class=\"language-text\">secrets</code> module provide appropriate entropy. Avoid using <code class=\"language-text\">Math.random()</code> or similar pseudorandom functions that lack cryptographic security.</p>\n<p><strong>Store Token Securely (Hashed or Encrypted)</strong></p>\n<p>Storing tokens in plain text creates unnecessary risk. If the database is compromised, attackers gain valid authentication tokens. Implement the same security measures used for password storage.</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"1836249754143093200\"\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 hashlib\nimport secrets\nfrom datetime import datetime, timedelta\nfrom sqlalchemy import Column, String, DateTime, Boolean\n\nclass MagicLinkToken(db.Model):\n    __tablename__ = 'magic_link_tokens'\n    \n    id = Column(String, primary_key=True)\n    token_hash = Column(String, nullable=False, index=True)\n    user_id = Column(String, nullable=False)\n    email = Column(String, nullable=False)\n    created_at = Column(DateTime, default=datetime.utcnow)\n    expires_at = Column(DateTime, nullable=False)\n    used = Column(Boolean, default=False)\n    used_at = Column(DateTime, nullable=True)\n    ip_address = Column(String, nullable=True)\n    user_agent = Column(String, nullable=True)\n\n    @classmethod\n    def create_token(cls, user_id, email, ip_address=None, user_agent=None):\n        raw_token = secrets.token_urlsafe(32)\n        \n        # Hash token for storage\n        token_hash = hashlib.sha256(raw_token.encode()).hexdigest()\n        \n        # Create database record\n        token_record = cls(\n            id=secrets.token_hex(16),\n            token_hash=token_hash,\n            user_id=user_id,\n            email=email,\n            expires_at=datetime.utcnow() + timedelta(minutes=15),\n            ip_address=ip_address,\n            user_agent=user_agent\n        )\n        \n        db.session.add(token_record)\n        db.session.commit()\n        \n        # Return raw token for email\n        return raw_token, token_record.id\n    \n    @classmethod\n    def verify_token(cls, raw_token):\n        token_hash = hashlib.sha256(raw_token.encode()).hexdigest()\n        \n        token_record = cls.query.filter_by(\n            token_hash=token_hash,\n            used=False\n        ).first()\n        \n        if not token_record:\n            return None\n        \n        if datetime.utcnow() > token_record.expires_at:\n            return None\n        \n        token_record.used = True\n        token_record.used_at = datetime.utcnow()\n        db.session.commit()\n        \n        return token_record`, `1836249754143093200`)\"\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=\"python\"><pre class=\"language-python\"><code class=\"language-python\"><span class=\"token keyword\">import</span> hashlib\n<span class=\"token keyword\">import</span> secrets\n<span class=\"token keyword\">from</span> datetime <span class=\"token keyword\">import</span> datetime<span class=\"token punctuation\">,</span> timedelta\n<span class=\"token keyword\">from</span> sqlalchemy <span class=\"token keyword\">import</span> Column<span class=\"token punctuation\">,</span> String<span class=\"token punctuation\">,</span> DateTime<span class=\"token punctuation\">,</span> Boolean\n\n<span class=\"token keyword\">class</span> <span class=\"token class-name\">MagicLinkToken</span><span class=\"token punctuation\">(</span>db<span class=\"token punctuation\">.</span>Model<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    __tablename__ <span class=\"token operator\">=</span> <span class=\"token string\">'magic_link_tokens'</span>\n    \n    <span class=\"token builtin\">id</span> <span class=\"token operator\">=</span> Column<span class=\"token punctuation\">(</span>String<span class=\"token punctuation\">,</span> primary_key<span class=\"token operator\">=</span><span class=\"token boolean\">True</span><span class=\"token punctuation\">)</span>\n    token_hash <span class=\"token operator\">=</span> Column<span class=\"token punctuation\">(</span>String<span class=\"token punctuation\">,</span> nullable<span class=\"token operator\">=</span><span class=\"token boolean\">False</span><span class=\"token punctuation\">,</span> index<span class=\"token operator\">=</span><span class=\"token boolean\">True</span><span class=\"token punctuation\">)</span>\n    user_id <span class=\"token operator\">=</span> Column<span class=\"token punctuation\">(</span>String<span class=\"token punctuation\">,</span> nullable<span class=\"token operator\">=</span><span class=\"token boolean\">False</span><span class=\"token punctuation\">)</span>\n    email <span class=\"token operator\">=</span> Column<span class=\"token punctuation\">(</span>String<span class=\"token punctuation\">,</span> nullable<span class=\"token operator\">=</span><span class=\"token boolean\">False</span><span class=\"token punctuation\">)</span>\n    created_at <span class=\"token operator\">=</span> Column<span class=\"token punctuation\">(</span>DateTime<span class=\"token punctuation\">,</span> default<span class=\"token operator\">=</span>datetime<span class=\"token punctuation\">.</span>utcnow<span class=\"token punctuation\">)</span>\n    expires_at <span class=\"token operator\">=</span> Column<span class=\"token punctuation\">(</span>DateTime<span class=\"token punctuation\">,</span> nullable<span class=\"token operator\">=</span><span class=\"token boolean\">False</span><span class=\"token punctuation\">)</span>\n    used <span class=\"token operator\">=</span> Column<span class=\"token punctuation\">(</span>Boolean<span class=\"token punctuation\">,</span> default<span class=\"token operator\">=</span><span class=\"token boolean\">False</span><span class=\"token punctuation\">)</span>\n    used_at <span class=\"token operator\">=</span> Column<span class=\"token punctuation\">(</span>DateTime<span class=\"token punctuation\">,</span> nullable<span class=\"token operator\">=</span><span class=\"token boolean\">True</span><span class=\"token punctuation\">)</span>\n    ip_address <span class=\"token operator\">=</span> Column<span class=\"token punctuation\">(</span>String<span class=\"token punctuation\">,</span> nullable<span class=\"token operator\">=</span><span class=\"token boolean\">True</span><span class=\"token punctuation\">)</span>\n    user_agent <span class=\"token operator\">=</span> Column<span class=\"token punctuation\">(</span>String<span class=\"token punctuation\">,</span> nullable<span class=\"token operator\">=</span><span class=\"token boolean\">True</span><span class=\"token punctuation\">)</span>\n\n    <span class=\"token decorator annotation punctuation\">@classmethod</span>\n    <span class=\"token keyword\">def</span> <span class=\"token function\">create_token</span><span class=\"token punctuation\">(</span>cls<span class=\"token punctuation\">,</span> user_id<span class=\"token punctuation\">,</span> email<span class=\"token punctuation\">,</span> ip_address<span class=\"token operator\">=</span><span class=\"token boolean\">None</span><span class=\"token punctuation\">,</span> user_agent<span class=\"token operator\">=</span><span class=\"token boolean\">None</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n        raw_token <span class=\"token operator\">=</span> secrets<span class=\"token punctuation\">.</span>token_urlsafe<span class=\"token punctuation\">(</span><span class=\"token number\">32</span><span class=\"token punctuation\">)</span>\n        \n        <span class=\"token comment\"># Hash token for storage</span>\n        token_hash <span class=\"token operator\">=</span> hashlib<span class=\"token punctuation\">.</span>sha256<span class=\"token punctuation\">(</span>raw_token<span class=\"token punctuation\">.</span>encode<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>hexdigest<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n        \n        <span class=\"token comment\"># Create database record</span>\n        token_record <span class=\"token operator\">=</span> cls<span class=\"token punctuation\">(</span>\n            <span class=\"token builtin\">id</span><span class=\"token operator\">=</span>secrets<span class=\"token punctuation\">.</span>token_hex<span class=\"token punctuation\">(</span><span class=\"token number\">16</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n            token_hash<span class=\"token operator\">=</span>token_hash<span class=\"token punctuation\">,</span>\n            user_id<span class=\"token operator\">=</span>user_id<span class=\"token punctuation\">,</span>\n            email<span class=\"token operator\">=</span>email<span class=\"token punctuation\">,</span>\n            expires_at<span class=\"token operator\">=</span>datetime<span class=\"token punctuation\">.</span>utcnow<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">+</span> timedelta<span class=\"token punctuation\">(</span>minutes<span class=\"token operator\">=</span><span class=\"token number\">15</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n            ip_address<span class=\"token operator\">=</span>ip_address<span class=\"token punctuation\">,</span>\n            user_agent<span class=\"token operator\">=</span>user_agent\n        <span class=\"token punctuation\">)</span>\n        \n        db<span class=\"token punctuation\">.</span>session<span class=\"token punctuation\">.</span>add<span class=\"token punctuation\">(</span>token_record<span class=\"token punctuation\">)</span>\n        db<span class=\"token punctuation\">.</span>session<span class=\"token punctuation\">.</span>commit<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n        \n        <span class=\"token comment\"># Return raw token for email</span>\n        <span class=\"token keyword\">return</span> raw_token<span class=\"token punctuation\">,</span> token_record<span class=\"token punctuation\">.</span><span class=\"token builtin\">id</span>\n    \n    <span class=\"token decorator annotation punctuation\">@classmethod</span>\n    <span class=\"token keyword\">def</span> <span class=\"token function\">verify_token</span><span class=\"token punctuation\">(</span>cls<span class=\"token punctuation\">,</span> raw_token<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n        token_hash <span class=\"token operator\">=</span> hashlib<span class=\"token punctuation\">.</span>sha256<span class=\"token punctuation\">(</span>raw_token<span class=\"token punctuation\">.</span>encode<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>hexdigest<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n        \n        token_record <span class=\"token operator\">=</span> cls<span class=\"token punctuation\">.</span>query<span class=\"token punctuation\">.</span>filter_by<span class=\"token punctuation\">(</span>\n            token_hash<span class=\"token operator\">=</span>token_hash<span class=\"token punctuation\">,</span>\n            used<span class=\"token operator\">=</span><span class=\"token boolean\">False</span>\n        <span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>first<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n        \n        <span class=\"token keyword\">if</span> <span class=\"token keyword\">not</span> token_record<span class=\"token punctuation\">:</span>\n            <span class=\"token keyword\">return</span> <span class=\"token boolean\">None</span>\n        \n        <span class=\"token keyword\">if</span> datetime<span class=\"token punctuation\">.</span>utcnow<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">></span> token_record<span class=\"token punctuation\">.</span>expires_at<span class=\"token punctuation\">:</span>\n            <span class=\"token keyword\">return</span> <span class=\"token boolean\">None</span>\n        \n        token_record<span class=\"token punctuation\">.</span>used <span class=\"token operator\">=</span> <span class=\"token boolean\">True</span>\n        token_record<span class=\"token punctuation\">.</span>used_at <span class=\"token operator\">=</span> datetime<span class=\"token punctuation\">.</span>utcnow<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n        db<span class=\"token punctuation\">.</span>session<span class=\"token punctuation\">.</span>commit<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n        \n        <span class=\"token keyword\">return</span> token_record</code></pre></div>\n<p><strong>Send Link Containing Token to User’s Email</strong></p>\n<p>Email delivery reliability directly impacts authentication success rates. Use transactional email services that provide delivery tracking and handle email provider quirks.</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"1310860871309449500\"\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(`const nodemailer = require('nodemailer');\nconst aws = require('@aws-sdk/client-ses');\n\nclass MagicLinkEmailService {\n  constructor() {\n    // Using Amazon SES \n    this.transporter = nodemailer.createTransporter({\n      SES: { \n        ses: new aws.SES({ region: 'us-east-1' }), \n        aws \n      }\n    });\n  }\n  \n  async sendMagicLink(email, token, metadata = {}) {\n    const magicLink = \\`\\${process.env.APP_URL}/auth/verify?token=\\${token}\\`;\n    \n    // Track email metrics\n    const messageId = crypto.randomUUID();\n    \n    const emailHtml = \\`\n      <!DOCTYPE html>\n      <html>\n        <head>\n          <meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;>\n        </head>\n        <body style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;&quot;>\n          <div style=&quot;max-width: 600px; margin: 0 auto; padding: 20px;&quot;>\n            <h2>Your Login Link</h2>\n            <p>Click the button below to log in to your account:</p>\n            <a href=&quot;\\${magicLink}&quot; \n               style=&quot;display: inline-block; \n                      padding: 12px 24px; \n                      background-color: #0066cc; \n                      color: white; \n                      text-decoration: none; \n                      border-radius: 4px;\n                      margin: 20px 0;&quot;>\n              Log In to Your Account\n            </a>\n            <p style=&quot;color: #666; font-size: 14px;&quot;>\n              This link expires in 15 minutes. If you didn't request this, please ignore this email.\n            </p>\n            <p style=&quot;color: #999; font-size: 12px;&quot;>\n              Having trouble? Copy and paste this link: \\${magicLink}\n            </p>\n          </div>\n        </body>\n      </html>\n    \\`;\n    \n    const mailOptions = {\n      from: \\`\\${process.env.APP_NAME} <noreply@\\${process.env.EMAIL_DOMAIN}>\\`,\n      to: email,\n      subject: 'Your login link',\n      html: emailHtml,\n      text: \\`Log in to your account: \\${magicLink}\\n\\nThis link expires in 15 minutes.\\`,\n      headers: {\n        'X-Message-ID': messageId,\n        'X-Entity-Ref-ID': metadata.userId\n      }\n    };\n    \n    try {\n      const info = await this.transporter.sendMail(mailOptions);\n      \n      // Log delivery attempt for monitoring\n      await this.logEmailSent({\n        messageId,\n        email,\n        provider: 'ses',\n        providerMessageId: info.messageId,\n        timestamp: new Date()\n      });\n      \n      return { success: true, messageId };\n    } catch (error) {\n      // Log failure for debugging\n      await this.logEmailFailed({\n        messageId,\n        email,\n        error: error.message,\n        timestamp: new Date()\n      });\n      \n      throw new EmailDeliveryError('Failed to send magic link');\n    }\n  }\n}`, `1310860871309449500`)\"\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\">const</span> nodemailer <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'nodemailer'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">const</span> aws <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'@aws-sdk/client-ses'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">class</span> <span class=\"token class-name\">MagicLinkEmailService</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token function\">constructor</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token comment\">// Using Amazon SES </span>\n    <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>transporter <span class=\"token operator\">=</span> nodemailer<span class=\"token punctuation\">.</span><span class=\"token function\">createTransporter</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n      <span class=\"token constant\">SES</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span> \n        <span class=\"token literal-property property\">ses</span><span class=\"token operator\">:</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">aws<span class=\"token punctuation\">.</span>SES</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">region</span><span class=\"token operator\">:</span> <span class=\"token string\">'us-east-1'</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> \n        aws \n      <span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n  \n  <span class=\"token keyword\">async</span> <span class=\"token function\">sendMagicLink</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">email<span class=\"token punctuation\">,</span> token<span class=\"token punctuation\">,</span> metadata <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">const</span> magicLink <span class=\"token operator\">=</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>process<span class=\"token punctuation\">.</span>env<span class=\"token punctuation\">.</span><span class=\"token constant\">APP_URL</span><span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">/auth/verify?token=</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>token<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">;</span>\n    \n    <span class=\"token comment\">// Track email metrics</span>\n    <span class=\"token keyword\">const</span> messageId <span class=\"token operator\">=</span> crypto<span class=\"token punctuation\">.</span><span class=\"token function\">randomUUID</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    \n    <span class=\"token keyword\">const</span> emailHtml <span class=\"token operator\">=</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">\n      &lt;!DOCTYPE html>\n      &lt;html>\n        &lt;head>\n          &lt;meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n        &lt;/head>\n        &lt;body style=\"font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\">\n          &lt;div style=\"max-width: 600px; margin: 0 auto; padding: 20px;\">\n            &lt;h2>Your Login Link&lt;/h2>\n            &lt;p>Click the button below to log in to your account:&lt;/p>\n            &lt;a href=\"</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>magicLink<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">\" \n               style=\"display: inline-block; \n                      padding: 12px 24px; \n                      background-color: #0066cc; \n                      color: white; \n                      text-decoration: none; \n                      border-radius: 4px;\n                      margin: 20px 0;\">\n              Log In to Your Account\n            &lt;/a>\n            &lt;p style=\"color: #666; font-size: 14px;\">\n              This link expires in 15 minutes. If you didn't request this, please ignore this email.\n            &lt;/p>\n            &lt;p style=\"color: #999; font-size: 12px;\">\n              Having trouble? Copy and paste this link: </span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>magicLink<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">\n            &lt;/p>\n          &lt;/div>\n        &lt;/body>\n      &lt;/html>\n    </span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">;</span>\n    \n    <span class=\"token keyword\">const</span> mailOptions <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token literal-property property\">from</span><span class=\"token operator\">:</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>process<span class=\"token punctuation\">.</span>env<span class=\"token punctuation\">.</span><span class=\"token constant\">APP_NAME</span><span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\"> &lt;noreply@</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>process<span class=\"token punctuation\">.</span>env<span class=\"token punctuation\">.</span><span class=\"token constant\">EMAIL_DOMAIN</span><span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span>\n      <span class=\"token literal-property property\">to</span><span class=\"token operator\">:</span> email<span class=\"token punctuation\">,</span>\n      <span class=\"token literal-property property\">subject</span><span class=\"token operator\">:</span> <span class=\"token string\">'Your login link'</span><span class=\"token punctuation\">,</span>\n      <span class=\"token literal-property property\">html</span><span class=\"token operator\">:</span> emailHtml<span class=\"token punctuation\">,</span>\n      <span class=\"token literal-property property\">text</span><span class=\"token operator\">:</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">Log in to your account: </span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>magicLink<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">\\n\\nThis link expires in 15 minutes.</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span>\n      <span class=\"token literal-property property\">headers</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token string-property property\">'X-Message-ID'</span><span class=\"token operator\">:</span> messageId<span class=\"token punctuation\">,</span>\n        <span class=\"token string-property property\">'X-Entity-Ref-ID'</span><span class=\"token operator\">:</span> metadata<span class=\"token punctuation\">.</span>userId\n      <span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n    \n    <span class=\"token keyword\">try</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">const</span> info <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>transporter<span class=\"token punctuation\">.</span><span class=\"token function\">sendMail</span><span class=\"token punctuation\">(</span>mailOptions<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n      \n      <span class=\"token comment\">// Log delivery attempt for monitoring</span>\n      <span class=\"token keyword\">await</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">logEmailSent</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n        messageId<span class=\"token punctuation\">,</span>\n        email<span class=\"token punctuation\">,</span>\n        <span class=\"token literal-property property\">provider</span><span class=\"token operator\">:</span> <span class=\"token string\">'ses'</span><span class=\"token punctuation\">,</span>\n        <span class=\"token literal-property property\">providerMessageId</span><span class=\"token operator\">:</span> info<span class=\"token punctuation\">.</span>messageId<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>\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n      \n      <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">success</span><span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span> messageId <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span> <span class=\"token keyword\">catch</span> <span class=\"token punctuation\">(</span>error<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token comment\">// Log failure for debugging</span>\n      <span class=\"token keyword\">await</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">logEmailFailed</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n        messageId<span class=\"token punctuation\">,</span>\n        email<span class=\"token punctuation\">,</span>\n        <span class=\"token literal-property property\">error</span><span class=\"token operator\">:</span> error<span class=\"token punctuation\">.</span>message<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>\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n      \n      <span class=\"token keyword\">throw</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">EmailDeliveryError</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Failed to send magic link'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p><strong>On Click, Verify Token and Authenticate Session</strong></p>\n<p>Token verification must handle multiple security checks before granting access. The verification endpoint needs protection against timing attacks and should provide clear error messages for debugging.</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"37019066194739820000\"\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(`const express = require('express');\nconst router = express.Router();\n\nrouter.get('/auth/verify', async (req, res) => {\n  const { token } = req.query;\n  \n  if (!token) {\n    return res.status(400).render('auth-error', {\n      error: 'Missing authentication token',\n      action: 'Request a new login link'\n    });\n  }\n  \n  try {\n    // Verify token and get user\n    const tokenRecord = await verifyMagicLinkToken(token);\n    \n    if (!tokenRecord) {\n      return res.status(401).render('auth-error', {\n        error: 'Invalid or expired link',\n        action: 'Request a new login link'\n      });\n    }\n    \n    // Additional security checks\n    if (tokenRecord.ipAddress && tokenRecord.ipAddress !== req.ip) {\n      await logSecurityEvent({\n        type: 'IP_MISMATCH',\n        userId: tokenRecord.userId,\n        originalIp: tokenRecord.ipAddress,\n        currentIp: req.ip\n      });\n      // Continue but flag for monitoring\n    }\n    \n    // Create session\n    const session = await createUserSession({\n      userId: tokenRecord.userId,\n      authMethod: 'magic_link',\n      ipAddress: req.ip,\n      userAgent: req.headers['user-agent']\n    });\n    \n    // Set secure session cookie\n    res.cookie('session', session.token, {\n      httpOnly: true,\n      secure: process.env.NODE_ENV === 'production',\n      sameSite: 'lax',\n      maxAge: 7 * 24 * 60 * 60 * 1000 // 7 days\n    });\n    \n    // Redirect to application\n    const redirectUrl = tokenRecord.redirectUrl || '/dashboard';\n    res.redirect(redirectUrl);\n    \n  } catch (error) {\n    console.error('Token verification error:', error);\n    res.status(500).render('auth-error', {\n      error: 'Authentication failed',\n      action: 'Please try again'\n    });\n  }\n});`, `37019066194739820000`)\"\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\">const</span> express <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'express'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">const</span> router <span class=\"token operator\">=</span> express<span class=\"token punctuation\">.</span><span class=\"token function\">Router</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\nrouter<span class=\"token punctuation\">.</span><span class=\"token function\">get</span><span class=\"token punctuation\">(</span><span class=\"token string\">'/auth/verify'</span><span class=\"token punctuation\">,</span> <span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">req<span class=\"token punctuation\">,</span> res</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> token <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> req<span class=\"token punctuation\">.</span>query<span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>token<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">return</span> res<span class=\"token punctuation\">.</span><span class=\"token function\">status</span><span class=\"token punctuation\">(</span><span class=\"token number\">400</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">render</span><span class=\"token punctuation\">(</span><span class=\"token string\">'auth-error'</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token literal-property property\">error</span><span class=\"token operator\">:</span> <span class=\"token string\">'Missing authentication token'</span><span class=\"token punctuation\">,</span>\n      <span class=\"token literal-property property\">action</span><span class=\"token operator\">:</span> <span class=\"token string\">'Request a new login link'</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n  \n  <span class=\"token keyword\">try</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token comment\">// Verify token and get user</span>\n    <span class=\"token keyword\">const</span> tokenRecord <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> <span class=\"token function\">verifyMagicLinkToken</span><span class=\"token punctuation\">(</span>token<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    \n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>tokenRecord<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">return</span> res<span class=\"token punctuation\">.</span><span class=\"token function\">status</span><span class=\"token punctuation\">(</span><span class=\"token number\">401</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">render</span><span class=\"token punctuation\">(</span><span class=\"token string\">'auth-error'</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token literal-property property\">error</span><span class=\"token operator\">:</span> <span class=\"token string\">'Invalid or expired link'</span><span class=\"token punctuation\">,</span>\n        <span class=\"token literal-property property\">action</span><span class=\"token operator\">:</span> <span class=\"token string\">'Request a new login link'</span>\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n    \n    <span class=\"token comment\">// Additional security checks</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>tokenRecord<span class=\"token punctuation\">.</span>ipAddress <span class=\"token operator\">&amp;&amp;</span> tokenRecord<span class=\"token punctuation\">.</span>ipAddress <span class=\"token operator\">!==</span> req<span class=\"token punctuation\">.</span>ip<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">await</span> <span class=\"token function\">logSecurityEvent</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n        <span class=\"token literal-property property\">type</span><span class=\"token operator\">:</span> <span class=\"token string\">'IP_MISMATCH'</span><span class=\"token punctuation\">,</span>\n        <span class=\"token literal-property property\">userId</span><span class=\"token operator\">:</span> tokenRecord<span class=\"token punctuation\">.</span>userId<span class=\"token punctuation\">,</span>\n        <span class=\"token literal-property property\">originalIp</span><span class=\"token operator\">:</span> tokenRecord<span class=\"token punctuation\">.</span>ipAddress<span class=\"token punctuation\">,</span>\n        <span class=\"token literal-property property\">currentIp</span><span class=\"token operator\">:</span> req<span class=\"token punctuation\">.</span>ip\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n      <span class=\"token comment\">// Continue but flag for monitoring</span>\n    <span class=\"token punctuation\">}</span>\n    \n    <span class=\"token comment\">// Create session</span>\n    <span class=\"token keyword\">const</span> session <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> <span class=\"token function\">createUserSession</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n      <span class=\"token literal-property property\">userId</span><span class=\"token operator\">:</span> tokenRecord<span class=\"token punctuation\">.</span>userId<span class=\"token punctuation\">,</span>\n      <span class=\"token literal-property property\">authMethod</span><span class=\"token operator\">:</span> <span class=\"token string\">'magic_link'</span><span class=\"token punctuation\">,</span>\n      <span class=\"token literal-property property\">ipAddress</span><span class=\"token operator\">:</span> req<span class=\"token punctuation\">.</span>ip<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>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    \n    <span class=\"token comment\">// Set secure session cookie</span>\n    res<span class=\"token punctuation\">.</span><span class=\"token function\">cookie</span><span class=\"token punctuation\">(</span><span class=\"token string\">'session'</span><span class=\"token punctuation\">,</span> session<span class=\"token punctuation\">.</span>token<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token literal-property property\">httpOnly</span><span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span>\n      <span class=\"token literal-property property\">secure</span><span class=\"token operator\">:</span> process<span class=\"token punctuation\">.</span>env<span class=\"token punctuation\">.</span><span class=\"token constant\">NODE_ENV</span> <span class=\"token operator\">===</span> <span class=\"token string\">'production'</span><span class=\"token punctuation\">,</span>\n      <span class=\"token literal-property property\">sameSite</span><span class=\"token operator\">:</span> <span class=\"token string\">'lax'</span><span class=\"token punctuation\">,</span>\n      <span class=\"token literal-property property\">maxAge</span><span class=\"token operator\">:</span> <span class=\"token number\">7</span> <span class=\"token operator\">*</span> <span class=\"token number\">24</span> <span class=\"token operator\">*</span> <span class=\"token number\">60</span> <span class=\"token operator\">*</span> <span class=\"token number\">60</span> <span class=\"token operator\">*</span> <span class=\"token number\">1000</span> <span class=\"token comment\">// 7 days</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    \n    <span class=\"token comment\">// Redirect to application</span>\n    <span class=\"token keyword\">const</span> redirectUrl <span class=\"token operator\">=</span> tokenRecord<span class=\"token punctuation\">.</span>redirectUrl <span class=\"token operator\">||</span> <span class=\"token string\">'/dashboard'</span><span class=\"token punctuation\">;</span>\n    res<span class=\"token punctuation\">.</span><span class=\"token function\">redirect</span><span class=\"token punctuation\">(</span>redirectUrl<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    \n  <span class=\"token punctuation\">}</span> <span class=\"token keyword\">catch</span> <span class=\"token punctuation\">(</span>error<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    console<span class=\"token punctuation\">.</span><span class=\"token function\">error</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Token verification error:'</span><span class=\"token punctuation\">,</span> error<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    res<span class=\"token punctuation\">.</span><span class=\"token function\">status</span><span class=\"token punctuation\">(</span><span class=\"token number\">500</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">render</span><span class=\"token punctuation\">(</span><span class=\"token string\">'auth-error'</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token literal-property property\">error</span><span class=\"token operator\">:</span> <span class=\"token string\">'Authentication failed'</span><span class=\"token punctuation\">,</span>\n      <span class=\"token literal-property property\">action</span><span class=\"token operator\">:</span> <span class=\"token string\">'Please try again'</span>\n    <span class=\"token punctuation\">}</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<h3 id=\"frontend-best-practices\" style=\"position:relative;\"><a href=\"#frontend-best-practices\" aria-label=\"frontend best practices 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>Frontend Best Practices</h3>\n<p>The user interface must provide clear feedback throughout the authentication process while handling edge cases gracefully.</p>\n<p><strong>Show Feedback (“Link sent to your email”)</strong></p>\n<p>Users need immediate confirmation that their authentication request was received and processed. Implement progressive UI states that guide users through the flow.</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"14596122166106374000\"\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 React, { useState } from 'react';\nimport { validateEmail } from './utils';\n\nfunction MagicLinkLogin() {\n  const [email, setEmail] = useState('');\n  const [status, setStatus] = useState('idle'); // idle, sending, sent, error\n  const [errorMessage, setErrorMessage] = useState('');\n  \n  const handleSubmit = async (e) => {\n    e.preventDefault();\n    \n    if (!validateEmail(email)) {\n      setErrorMessage('Please enter a valid email address');\n      return;\n    }\n    \n    setStatus('sending');\n    setErrorMessage('');\n    \n    try {\n      const response = await fetch('/api/auth/magic-link', {\n        method: 'POST',\n        headers: { 'Content-Type': 'application/json' },\n        body: JSON.stringify({ email })\n      });\n      \n      const data = await response.json();\n      \n      if (!response.ok) {\n        throw new Error(data.message || 'Failed to send login link');\n      }\n      \n      setStatus('sent');\n      \n      // Show success state for sufficient time\n      setTimeout(() => {\n        // Keep success message visible\n      }, 5000);\n      \n    } catch (error) {\n      setStatus('error');\n      setErrorMessage(error.message);\n    }\n  };\n  \n  return (\n    <div className=&quot;auth-container&quot;>\n      {status === 'sent' ? (\n        <div className=&quot;success-message&quot;>\n          <svg className=&quot;check-icon&quot; viewBox=&quot;0 0 24 24&quot;>\n            <path d=&quot;M9 11l3 3L22 4&quot; />\n          </svg>\n          <h2>Check your email!</h2>\n          <p>We sent a login link to <strong>{email}</strong></p>\n          <p className=&quot;helper-text&quot;>\n            The link expires in 15 minutes. Didn't receive it?\n            <button \n              onClick={() => setStatus('idle')}\n              className=&quot;link-button&quot;\n            >\n              Try again\n            </button>\n          </p>\n        </div>\n      ) : (\n        <form onSubmit={handleSubmit}>\n          <h2>Sign in with email</h2>\n          <input\n            type=&quot;email&quot;\n            value={email}\n            onChange={(e) => setEmail(e.target.value)}\n            placeholder=&quot;Enter your email&quot;\n            disabled={status === 'sending'}\n            aria-label=&quot;Email address&quot;\n            autoComplete=&quot;email&quot;\n          />\n          \n          {errorMessage && (\n            <div className=&quot;error-message&quot; role=&quot;alert&quot;>\n              {errorMessage}\n            </div>\n          )}\n          \n          <button \n            type=&quot;submit&quot; \n            disabled={status === 'sending'}\n            className={\\`submit-button \\${status === 'sending' ? 'loading' : ''}\\`}\n          >\n            {status === 'sending' ? (\n              <>\n                <span className=&quot;spinner&quot; />\n                Sending link...\n              </>\n            ) : (\n              'Send login link'\n            )}\n          </button>\n        </form>\n      )}\n    </div>\n  );\n}`, `14596122166106374000`)\"\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> React<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span> useState <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react'</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> validateEmail <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'./utils'</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">MagicLinkLogin</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>email<span class=\"token punctuation\">,</span> setEmail<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token string\">''</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>status<span class=\"token punctuation\">,</span> setStatus<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token string\">'idle'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// idle, sending, sent, error</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>errorMessage<span class=\"token punctuation\">,</span> setErrorMessage<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token string\">''</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">handleSubmit</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">e</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    e<span class=\"token punctuation\">.</span><span class=\"token function\">preventDefault</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    \n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span><span class=\"token function\">validateEmail</span><span class=\"token punctuation\">(</span>email<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token function\">setErrorMessage</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Please enter a valid email address'</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 punctuation\">}</span>\n    \n    <span class=\"token function\">setStatus</span><span class=\"token punctuation\">(</span><span class=\"token string\">'sending'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token function\">setErrorMessage</span><span class=\"token punctuation\">(</span><span class=\"token string\">''</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    \n    <span class=\"token keyword\">try</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">const</span> response <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> <span class=\"token function\">fetch</span><span class=\"token punctuation\">(</span><span class=\"token string\">'/api/auth/magic-link'</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token literal-property property\">method</span><span class=\"token operator\">:</span> <span class=\"token string\">'POST'</span><span class=\"token punctuation\">,</span>\n        <span class=\"token literal-property property\">headers</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span> <span class=\"token string-property property\">'Content-Type'</span><span class=\"token operator\">:</span> <span class=\"token string\">'application/json'</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n        <span class=\"token literal-property property\">body</span><span class=\"token operator\">:</span> <span class=\"token constant\">JSON</span><span class=\"token punctuation\">.</span><span class=\"token function\">stringify</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> email <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 keyword\">const</span> data <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> response<span class=\"token punctuation\">.</span><span class=\"token function\">json</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n      \n      <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>response<span class=\"token punctuation\">.</span>ok<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">throw</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Error</span><span class=\"token punctuation\">(</span>data<span class=\"token punctuation\">.</span>message <span class=\"token operator\">||</span> <span class=\"token string\">'Failed to send login link'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n      <span class=\"token punctuation\">}</span>\n      \n      <span class=\"token function\">setStatus</span><span class=\"token punctuation\">(</span><span class=\"token string\">'sent'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n      \n      <span class=\"token comment\">// Show success state for sufficient time</span>\n      <span class=\"token function\">setTimeout</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n        <span class=\"token comment\">// Keep success message visible</span>\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token number\">5000</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n      \n    <span class=\"token punctuation\">}</span> <span class=\"token keyword\">catch</span> <span class=\"token punctuation\">(</span>error<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token function\">setStatus</span><span class=\"token punctuation\">(</span><span class=\"token string\">'error'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n      <span class=\"token function\">setErrorMessage</span><span class=\"token punctuation\">(</span>error<span class=\"token punctuation\">.</span>message<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>\n  \n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>div className<span class=\"token operator\">=</span><span class=\"token string\">\"auth-container\"</span><span class=\"token operator\">></span>\n      <span class=\"token punctuation\">{</span>status <span class=\"token operator\">===</span> <span class=\"token string\">'sent'</span> <span class=\"token operator\">?</span> <span class=\"token punctuation\">(</span>\n        <span class=\"token operator\">&lt;</span>div className<span class=\"token operator\">=</span><span class=\"token string\">\"success-message\"</span><span class=\"token operator\">></span>\n          <span class=\"token operator\">&lt;</span>svg className<span class=\"token operator\">=</span><span class=\"token string\">\"check-icon\"</span> viewBox<span class=\"token operator\">=</span><span class=\"token string\">\"0 0 24 24\"</span><span class=\"token operator\">></span>\n            <span class=\"token operator\">&lt;</span>path d<span class=\"token operator\">=</span><span class=\"token string\">\"M9 11l3 3L22 4\"</span> <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n          <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>svg<span class=\"token operator\">></span>\n          <span class=\"token operator\">&lt;</span>h2<span class=\"token operator\">></span>Check your email<span class=\"token operator\">!</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>h2<span class=\"token operator\">></span>\n          <span class=\"token operator\">&lt;</span>p<span class=\"token operator\">></span>We sent a login link to <span class=\"token operator\">&lt;</span>strong<span class=\"token operator\">></span><span class=\"token punctuation\">{</span>email<span class=\"token punctuation\">}</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>strong<span class=\"token operator\">></span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>p<span class=\"token operator\">></span>\n          <span class=\"token operator\">&lt;</span>p className<span class=\"token operator\">=</span><span class=\"token string\">\"helper-text\"</span><span class=\"token operator\">></span>\n            The link expires <span class=\"token keyword\">in</span> <span class=\"token number\">15</span> minutes<span class=\"token punctuation\">.</span> Didn't receive it<span class=\"token operator\">?</span>\n            <span class=\"token operator\">&lt;</span>button \n              onClick<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token function\">setStatus</span><span class=\"token punctuation\">(</span><span class=\"token string\">'idle'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span>\n              className<span class=\"token operator\">=</span><span class=\"token string\">\"link-button\"</span>\n            <span class=\"token operator\">></span>\n              Try again\n            <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>button<span class=\"token operator\">></span>\n          <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>p<span class=\"token operator\">></span>\n        <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n      <span class=\"token punctuation\">)</span> <span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span>\n        <span class=\"token operator\">&lt;</span>form onSubmit<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>handleSubmit<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n          <span class=\"token operator\">&lt;</span>h2<span class=\"token operator\">></span>Sign <span class=\"token keyword\">in</span> <span class=\"token keyword\">with</span> email<span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>h2<span class=\"token operator\">></span>\n          <span class=\"token operator\">&lt;</span>input\n            type<span class=\"token operator\">=</span><span class=\"token string\">\"email\"</span>\n            value<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>email<span class=\"token punctuation\">}</span>\n            onChange<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">e</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token function\">setEmail</span><span class=\"token punctuation\">(</span>e<span class=\"token punctuation\">.</span>target<span class=\"token punctuation\">.</span>value<span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span>\n            placeholder<span class=\"token operator\">=</span><span class=\"token string\">\"Enter your email\"</span>\n            disabled<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>status <span class=\"token operator\">===</span> <span class=\"token string\">'sending'</span><span class=\"token punctuation\">}</span>\n            aria<span class=\"token operator\">-</span>label<span class=\"token operator\">=</span><span class=\"token string\">\"Email address\"</span>\n            autoComplete<span class=\"token operator\">=</span><span class=\"token string\">\"email\"</span>\n          <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n          \n          <span class=\"token punctuation\">{</span>errorMessage <span class=\"token operator\">&amp;&amp;</span> <span class=\"token punctuation\">(</span>\n            <span class=\"token operator\">&lt;</span>div className<span class=\"token operator\">=</span><span class=\"token string\">\"error-message\"</span> role<span class=\"token operator\">=</span><span class=\"token string\">\"alert\"</span><span class=\"token operator\">></span>\n              <span class=\"token punctuation\">{</span>errorMessage<span class=\"token punctuation\">}</span>\n            <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n          <span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span>\n          \n          <span class=\"token operator\">&lt;</span>button \n            type<span class=\"token operator\">=</span><span class=\"token string\">\"submit\"</span> \n            disabled<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>status <span class=\"token operator\">===</span> <span class=\"token string\">'sending'</span><span class=\"token punctuation\">}</span>\n            className<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">submit-button </span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>status <span class=\"token operator\">===</span> <span class=\"token string\">'sending'</span> <span class=\"token operator\">?</span> <span class=\"token string\">'loading'</span> <span class=\"token operator\">:</span> <span class=\"token string\">''</span><span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">}</span>\n          <span class=\"token operator\">></span>\n            <span class=\"token punctuation\">{</span>status <span class=\"token operator\">===</span> <span class=\"token string\">'sending'</span> <span class=\"token operator\">?</span> <span class=\"token punctuation\">(</span>\n              <span class=\"token operator\">&lt;</span><span class=\"token operator\">></span>\n                <span class=\"token operator\">&lt;</span>span className<span class=\"token operator\">=</span><span class=\"token string\">\"spinner\"</span> <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n                Sending link<span class=\"token operator\">...</span>\n              <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span><span class=\"token operator\">></span>\n            <span class=\"token punctuation\">)</span> <span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span>\n              <span class=\"token string\">'Send login link'</span>\n            <span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span>\n          <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>button<span class=\"token operator\">></span>\n        <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>form<span class=\"token operator\">></span>\n      <span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<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>Handle Errors Gracefully (Expired, Used, or Invalid Link)</strong></p>\n<p>Error handling requires balancing security with user experience. Provide helpful guidance without revealing sensitive information about the authentication system.</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"21428970119981085000\"\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(`interface AuthError {\n  code: string;\n  message: string;\n  action: string;\n}\n\nclass MagicLinkErrorHandler {\n  private static readonly ERROR_MESSAGES: Record<string, AuthError> = {\n    TOKEN_EXPIRED: {\n      code: 'TOKEN_EXPIRED',\n      message: 'This login link has expired',\n      action: 'Request a new link to sign in'\n    },\n    TOKEN_USED: {\n      code: 'TOKEN_USED',\n      message: 'This login link has already been used',\n      action: 'Request a new link to sign in'\n    },\n    TOKEN_INVALID: {\n      code: 'TOKEN_INVALID',\n      message: 'This login link is invalid',\n      action: 'Make sure you clicked the correct link or request a new one'\n    },\n    RATE_LIMITED: {\n      code: 'RATE_LIMITED',\n      message: 'Too many login attempts',\n      action: 'Please wait a few minutes before requesting another link'\n    }\n  };\n  \n  static handleVerificationError(error: any): AuthError {\n    // Map specific errors to user-friendly messages\n    const errorCode = error?.code || 'TOKEN_INVALID';\n    return this.ERROR_MESSAGES[errorCode] || this.ERROR_MESSAGES.TOKEN_INVALID;\n  }\n  \n  static createErrorPage(error: AuthError): string {\n    return \\`\n      <div class=&quot;error-container&quot;>\n        <div class=&quot;error-icon&quot;>⚠️</div>\n        <h1>\\${error.message}</h1>\n        <p>\\${error.action}</p>\n        <a href=&quot;/login&quot; class=&quot;button&quot;>Back to login</a>\n      </div>\n    \\`;\n  }\n}`, `21428970119981085000`)\"\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=\"typescript\"><pre class=\"language-typescript\"><code class=\"language-typescript\"><span class=\"token keyword\">interface</span> <span class=\"token class-name\">AuthError</span> <span class=\"token punctuation\">{</span>\n  code<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span>\n  message<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span>\n  action<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">class</span> <span class=\"token class-name\">MagicLinkErrorHandler</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">private</span> <span class=\"token keyword\">static</span> <span class=\"token keyword\">readonly</span> <span class=\"token constant\">ERROR_MESSAGES</span><span class=\"token operator\">:</span> Record<span class=\"token operator\">&lt;</span><span class=\"token builtin\">string</span><span class=\"token punctuation\">,</span> AuthError<span class=\"token operator\">></span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token constant\">TOKEN_EXPIRED</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n      code<span class=\"token operator\">:</span> <span class=\"token string\">'TOKEN_EXPIRED'</span><span class=\"token punctuation\">,</span>\n      message<span class=\"token operator\">:</span> <span class=\"token string\">'This login link has expired'</span><span class=\"token punctuation\">,</span>\n      action<span class=\"token operator\">:</span> <span class=\"token string\">'Request a new link to sign in'</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n    <span class=\"token constant\">TOKEN_USED</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n      code<span class=\"token operator\">:</span> <span class=\"token string\">'TOKEN_USED'</span><span class=\"token punctuation\">,</span>\n      message<span class=\"token operator\">:</span> <span class=\"token string\">'This login link has already been used'</span><span class=\"token punctuation\">,</span>\n      action<span class=\"token operator\">:</span> <span class=\"token string\">'Request a new link to sign in'</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n    <span class=\"token constant\">TOKEN_INVALID</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n      code<span class=\"token operator\">:</span> <span class=\"token string\">'TOKEN_INVALID'</span><span class=\"token punctuation\">,</span>\n      message<span class=\"token operator\">:</span> <span class=\"token string\">'This login link is invalid'</span><span class=\"token punctuation\">,</span>\n      action<span class=\"token operator\">:</span> <span class=\"token string\">'Make sure you clicked the correct link or request a new one'</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n    <span class=\"token constant\">RATE_LIMITED</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n      code<span class=\"token operator\">:</span> <span class=\"token string\">'RATE_LIMITED'</span><span class=\"token punctuation\">,</span>\n      message<span class=\"token operator\">:</span> <span class=\"token string\">'Too many login attempts'</span><span class=\"token punctuation\">,</span>\n      action<span class=\"token operator\">:</span> <span class=\"token string\">'Please wait a few minutes before requesting another link'</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token keyword\">static</span> <span class=\"token function\">handleVerificationError</span><span class=\"token punctuation\">(</span>error<span class=\"token operator\">:</span> <span class=\"token builtin\">any</span><span class=\"token punctuation\">)</span><span class=\"token operator\">:</span> AuthError <span class=\"token punctuation\">{</span>\n    <span class=\"token comment\">// Map specific errors to user-friendly messages</span>\n    <span class=\"token keyword\">const</span> errorCode <span class=\"token operator\">=</span> error<span class=\"token operator\">?.</span>code <span class=\"token operator\">||</span> <span class=\"token string\">'TOKEN_INVALID'</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">return</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token constant\">ERROR_MESSAGES</span><span class=\"token punctuation\">[</span>errorCode<span class=\"token punctuation\">]</span> <span class=\"token operator\">||</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token constant\">ERROR_MESSAGES</span><span class=\"token punctuation\">.</span><span class=\"token constant\">TOKEN_INVALID</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n  \n  <span class=\"token keyword\">static</span> <span class=\"token function\">createErrorPage</span><span class=\"token punctuation\">(</span>error<span class=\"token operator\">:</span> AuthError<span class=\"token punctuation\">)</span><span class=\"token operator\">:</span> <span class=\"token builtin\">string</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">return</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">\n      &lt;div class=\"error-container\">\n        &lt;div class=\"error-icon\">⚠️&lt;/div>\n        &lt;h1></span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>error<span class=\"token punctuation\">.</span>message<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">&lt;/h1>\n        &lt;p></span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>error<span class=\"token punctuation\">.</span>action<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">&lt;/p>\n        &lt;a href=\"/login\" class=\"button\">Back to login&lt;/a>\n      &lt;/div>\n    </span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<h3 id=\"security-recommendations\" style=\"position:relative;\"><a href=\"#security-recommendations\" aria-label=\"security recommendations 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 Recommendations</h3>\n<p>Production magic link systems require multiple security layers to prevent abuse and protect user accounts.</p>\n<p><strong>Expiration Time (15 Minutes)</strong></p>\n<p>Token lifetime balances security with usability. Shorter expiration times reduce risk but may frustrate users who don’t check email immediately. Industry practice converges on 15 to 30 minute windows.</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"28024140942563512000\"\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(`class TokenExpirationPolicy {\n  static readonly DEFAULT_EXPIRY = 15 * 60 * 1000; // 15 minutes\n  static readonly MAX_EXPIRY = 60 * 60 * 1000; // 1 hour\n  static readonly MIN_EXPIRY = 5 * 60 * 1000; // 5 minutes\n  \n  static calculateExpiry(userContext) {\n    // Adjust expiration based on risk factors\n    let expiryMs = this.DEFAULT_EXPIRY;\n    \n    if (userContext.isHighValue) {\n      // Shorter expiry for admin accounts\n      expiryMs = this.MIN_EXPIRY;\n    } else if (userContext.trustedDevice) {\n      // Slightly longer for recognized devices\n      expiryMs = 20 * 60 * 1000;\n    }\n    \n    return new Date(Date.now() + expiryMs);\n  }\n  \n  static isExpired(expiresAt) {\n    return new Date() > new Date(expiresAt);\n  }\n}`, `28024140942563512000`)\"\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\">class</span> <span class=\"token class-name\">TokenExpirationPolicy</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">static</span> readonly <span class=\"token constant\">DEFAULT_EXPIRY</span> <span class=\"token operator\">=</span> <span class=\"token number\">15</span> <span class=\"token operator\">*</span> <span class=\"token number\">60</span> <span class=\"token operator\">*</span> <span class=\"token number\">1000</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// 15 minutes</span>\n  <span class=\"token keyword\">static</span> readonly <span class=\"token constant\">MAX_EXPIRY</span> <span class=\"token operator\">=</span> <span class=\"token number\">60</span> <span class=\"token operator\">*</span> <span class=\"token number\">60</span> <span class=\"token operator\">*</span> <span class=\"token number\">1000</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// 1 hour</span>\n  <span class=\"token keyword\">static</span> readonly <span class=\"token constant\">MIN_EXPIRY</span> <span class=\"token operator\">=</span> <span class=\"token number\">5</span> <span class=\"token operator\">*</span> <span class=\"token number\">60</span> <span class=\"token operator\">*</span> <span class=\"token number\">1000</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// 5 minutes</span>\n  \n  <span class=\"token keyword\">static</span> <span class=\"token function\">calculateExpiry</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">userContext</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token comment\">// Adjust expiration based on risk factors</span>\n    <span class=\"token keyword\">let</span> expiryMs <span class=\"token operator\">=</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token constant\">DEFAULT_EXPIRY</span><span class=\"token punctuation\">;</span>\n    \n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>userContext<span class=\"token punctuation\">.</span>isHighValue<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token comment\">// Shorter expiry for admin accounts</span>\n      expiryMs <span class=\"token operator\">=</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token constant\">MIN_EXPIRY</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span> <span class=\"token keyword\">else</span> <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>userContext<span class=\"token punctuation\">.</span>trustedDevice<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token comment\">// Slightly longer for recognized devices</span>\n      expiryMs <span class=\"token operator\">=</span> <span class=\"token number\">20</span> <span class=\"token operator\">*</span> <span class=\"token number\">60</span> <span class=\"token operator\">*</span> <span class=\"token number\">1000</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n    \n    <span class=\"token keyword\">return</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Date</span><span class=\"token punctuation\">(</span>Date<span class=\"token punctuation\">.</span><span class=\"token function\">now</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">+</span> expiryMs<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n  \n  <span class=\"token keyword\">static</span> <span class=\"token function\">isExpired</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">expiresAt</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">return</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 operator\">></span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Date</span><span class=\"token punctuation\">(</span>expiresAt<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p><strong>Single-Use Enforcement</strong></p>\n<p>Tokens must become invalid immediately after successful use. This prevents replay attacks and limits damage from compromised tokens.</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"36719062151379080000\"\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(`-- Atomic single use \nCREATE TABLE magic_link_tokens (\n    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),\n    token_hash VARCHAR(64) NOT NULL,\n    user_id UUID NOT NULL,\n    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n    expires_at TIMESTAMP NOT NULL,\n    used_at TIMESTAMP,\n    ip_address INET,\n    user_agent TEXT,\n    CONSTRAINT unique_unused_token UNIQUE (token_hash)\n);\n\n-- Atomic token consumption\nCREATE OR REPLACE FUNCTION consume_magic_token(\n    p_token_hash VARCHAR(64)\n) RETURNS TABLE(user_id UUID, email VARCHAR) AS \\$\\$\nBEGIN\n    RETURN QUERY\n    UPDATE magic_link_tokens\n    SET used_at = CURRENT_TIMESTAMP\n    WHERE token_hash = p_token_hash\n      AND used_at IS NULL\n      AND expires_at > CURRENT_TIMESTAMP\n    RETURNING user_id, email;\nEND;\n\\$\\$ LANGUAGE plpgsql;`, `36719062151379080000`)\"\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=\"sql\"><pre class=\"language-sql\"><code class=\"language-sql\"><span class=\"token comment\">-- Atomic single use </span>\n<span class=\"token keyword\">CREATE</span> <span class=\"token keyword\">TABLE</span> magic_link_tokens <span class=\"token punctuation\">(</span>\n    id UUID <span class=\"token keyword\">PRIMARY</span> <span class=\"token keyword\">KEY</span> <span class=\"token keyword\">DEFAULT</span> gen_random_uuid<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n    token_hash <span class=\"token keyword\">VARCHAR</span><span class=\"token punctuation\">(</span><span class=\"token number\">64</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">NOT</span> <span class=\"token boolean\">NULL</span><span class=\"token punctuation\">,</span>\n    user_id UUID <span class=\"token operator\">NOT</span> <span class=\"token boolean\">NULL</span><span class=\"token punctuation\">,</span>\n    created_at <span class=\"token keyword\">TIMESTAMP</span> <span class=\"token keyword\">DEFAULT</span> <span class=\"token keyword\">CURRENT_TIMESTAMP</span><span class=\"token punctuation\">,</span>\n    expires_at <span class=\"token keyword\">TIMESTAMP</span> <span class=\"token operator\">NOT</span> <span class=\"token boolean\">NULL</span><span class=\"token punctuation\">,</span>\n    used_at <span class=\"token keyword\">TIMESTAMP</span><span class=\"token punctuation\">,</span>\n    ip_address INET<span class=\"token punctuation\">,</span>\n    user_agent <span class=\"token keyword\">TEXT</span><span class=\"token punctuation\">,</span>\n    <span class=\"token keyword\">CONSTRAINT</span> unique_unused_token <span class=\"token keyword\">UNIQUE</span> <span class=\"token punctuation\">(</span>token_hash<span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\">-- Atomic token consumption</span>\n<span class=\"token keyword\">CREATE</span> <span class=\"token operator\">OR</span> <span class=\"token keyword\">REPLACE</span> <span class=\"token keyword\">FUNCTION</span> consume_magic_token<span class=\"token punctuation\">(</span>\n    p_token_hash <span class=\"token keyword\">VARCHAR</span><span class=\"token punctuation\">(</span><span class=\"token number\">64</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">)</span> <span class=\"token keyword\">RETURNS</span> <span class=\"token keyword\">TABLE</span><span class=\"token punctuation\">(</span>user_id UUID<span class=\"token punctuation\">,</span> email <span class=\"token keyword\">VARCHAR</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">AS</span> $$\n<span class=\"token keyword\">BEGIN</span>\n    <span class=\"token keyword\">RETURN</span> QUERY\n    <span class=\"token keyword\">UPDATE</span> magic_link_tokens\n    <span class=\"token keyword\">SET</span> used_at <span class=\"token operator\">=</span> <span class=\"token keyword\">CURRENT_TIMESTAMP</span>\n    <span class=\"token keyword\">WHERE</span> token_hash <span class=\"token operator\">=</span> p_token_hash\n      <span class=\"token operator\">AND</span> used_at <span class=\"token operator\">IS</span> <span class=\"token boolean\">NULL</span>\n      <span class=\"token operator\">AND</span> expires_at <span class=\"token operator\">></span> <span class=\"token keyword\">CURRENT_TIMESTAMP</span>\n    <span class=\"token keyword\">RETURNING</span> user_id<span class=\"token punctuation\">,</span> email<span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">END</span><span class=\"token punctuation\">;</span>\n$$ <span class=\"token keyword\">LANGUAGE</span> plpgsql<span class=\"token punctuation\">;</span></code></pre></div>\n<p><strong>IP/Device Fingerprinting (Optional for Higher Security)</strong></p>\n<p>Additional verification layers can detect suspicious authentication attempts without adding user friction.</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"34626987627594530000\"\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(`const crypto = require('crypto');\n\nclass DeviceFingerprint {\n  static generate(request) {\n    const components = [\n      request.headers['user-agent'],\n      request.headers['accept-language'],\n      request.headers['accept-encoding'],\n      this.getScreenResolution(request),\n      this.getTimezone(request)\n    ];\n    \n    const fingerprintString = components\n      .filter(Boolean)\n      .join('|');\n    \n    return crypto\n      .createHash('sha256')\n      .update(fingerprintString)\n      .digest('hex');\n  }\n  \n  static async verify(storedFingerprint, currentRequest, tolerance = 0.8) {\n    const currentFingerprint = this.generate(currentRequest);\n    \n    if (storedFingerprint === currentFingerprint) {\n      return { match: true, confidence: 1.0 };\n    }\n    \n    // Fuzzy matching for minor changes\n    const similarity = this.calculateSimilarity(\n      storedFingerprint, \n      currentFingerprint\n    );\n    \n    return {\n      match: similarity >= tolerance,\n      confidence: similarity\n    };\n  }\n  \n  static riskAssessment(tokenData, currentRequest) {\n    const risks = [];\n    \n    // IP address change\n    if (tokenData.ipAddress !== currentRequest.ip) {\n      const distance = this.calculateGeoDistance(\n        tokenData.ipAddress,\n        currentRequest.ip\n      );\n      \n      if (distance > 100) { // More than 100km\n        risks.push({\n          factor: 'ip_location_change',\n          severity: distance > 1000 ? 'high' : 'medium'\n        });\n      }\n    }\n    \n    // Time based analysis\n    const timeSinceCreation = Date.now() - tokenData.createdAt;\n    if (timeSinceCreation < 2000) { // Less than 2 seconds\n      risks.push({\n        factor: 'too_fast',\n        severity: 'medium'\n      });\n    }\n    \n    return {\n      riskLevel: this.calculateOverallRisk(risks),\n      factors: risks\n    };\n  }\n}`, `34626987627594530000`)\"\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\">const</span> crypto <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'crypto'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">class</span> <span class=\"token class-name\">DeviceFingerprint</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">static</span> <span class=\"token function\">generate</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">request</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">const</span> components <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span>\n      request<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      request<span class=\"token punctuation\">.</span>headers<span class=\"token punctuation\">[</span><span class=\"token string\">'accept-language'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n      request<span class=\"token punctuation\">.</span>headers<span class=\"token punctuation\">[</span><span class=\"token string\">'accept-encoding'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n      <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">getScreenResolution</span><span class=\"token punctuation\">(</span>request<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n      <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">getTimezone</span><span class=\"token punctuation\">(</span>request<span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span>\n    \n    <span class=\"token keyword\">const</span> fingerprintString <span class=\"token operator\">=</span> components\n      <span class=\"token punctuation\">.</span><span class=\"token function\">filter</span><span class=\"token punctuation\">(</span>Boolean<span class=\"token punctuation\">)</span>\n      <span class=\"token punctuation\">.</span><span class=\"token function\">join</span><span class=\"token punctuation\">(</span><span class=\"token string\">'|'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    \n    <span class=\"token keyword\">return</span> crypto\n      <span class=\"token punctuation\">.</span><span class=\"token function\">createHash</span><span class=\"token punctuation\">(</span><span class=\"token string\">'sha256'</span><span class=\"token punctuation\">)</span>\n      <span class=\"token punctuation\">.</span><span class=\"token function\">update</span><span class=\"token punctuation\">(</span>fingerprintString<span class=\"token punctuation\">)</span>\n      <span class=\"token punctuation\">.</span><span class=\"token function\">digest</span><span class=\"token punctuation\">(</span><span class=\"token string\">'hex'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n  \n  <span class=\"token keyword\">static</span> <span class=\"token keyword\">async</span> <span class=\"token function\">verify</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">storedFingerprint<span class=\"token punctuation\">,</span> currentRequest<span class=\"token punctuation\">,</span> tolerance <span class=\"token operator\">=</span> <span class=\"token number\">0.8</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">const</span> currentFingerprint <span class=\"token operator\">=</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">generate</span><span class=\"token punctuation\">(</span>currentRequest<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    \n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>storedFingerprint <span class=\"token operator\">===</span> currentFingerprint<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">match</span><span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span> <span class=\"token literal-property property\">confidence</span><span class=\"token operator\">:</span> <span class=\"token number\">1.0</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n    \n    <span class=\"token comment\">// Fuzzy matching for minor changes</span>\n    <span class=\"token keyword\">const</span> similarity <span class=\"token operator\">=</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">calculateSimilarity</span><span class=\"token punctuation\">(</span>\n      storedFingerprint<span class=\"token punctuation\">,</span> \n      currentFingerprint\n    <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    \n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token literal-property property\">match</span><span class=\"token operator\">:</span> similarity <span class=\"token operator\">>=</span> tolerance<span class=\"token punctuation\">,</span>\n      <span class=\"token literal-property property\">confidence</span><span class=\"token operator\">:</span> similarity\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n  \n  <span class=\"token keyword\">static</span> <span class=\"token function\">riskAssessment</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">tokenData<span class=\"token punctuation\">,</span> currentRequest</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">const</span> risks <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span>\n    \n    <span class=\"token comment\">// IP address change</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>tokenData<span class=\"token punctuation\">.</span>ipAddress <span class=\"token operator\">!==</span> currentRequest<span class=\"token punctuation\">.</span>ip<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">const</span> distance <span class=\"token operator\">=</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">calculateGeoDistance</span><span class=\"token punctuation\">(</span>\n        tokenData<span class=\"token punctuation\">.</span>ipAddress<span class=\"token punctuation\">,</span>\n        currentRequest<span class=\"token punctuation\">.</span>ip\n      <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n      \n      <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>distance <span class=\"token operator\">></span> <span class=\"token number\">100</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span> <span class=\"token comment\">// More than 100km</span>\n        risks<span class=\"token punctuation\">.</span><span class=\"token function\">push</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n          <span class=\"token literal-property property\">factor</span><span class=\"token operator\">:</span> <span class=\"token string\">'ip_location_change'</span><span class=\"token punctuation\">,</span>\n          <span class=\"token literal-property property\">severity</span><span class=\"token operator\">:</span> distance <span class=\"token operator\">></span> <span class=\"token number\">1000</span> <span class=\"token operator\">?</span> <span class=\"token string\">'high'</span> <span class=\"token operator\">:</span> <span class=\"token string\">'medium'</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n      <span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">}</span>\n    \n    <span class=\"token comment\">// Time based analysis</span>\n    <span class=\"token keyword\">const</span> timeSinceCreation <span class=\"token operator\">=</span> Date<span class=\"token punctuation\">.</span><span class=\"token function\">now</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">-</span> tokenData<span class=\"token punctuation\">.</span>createdAt<span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>timeSinceCreation <span class=\"token operator\">&lt;</span> <span class=\"token number\">2000</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span> <span class=\"token comment\">// Less than 2 seconds</span>\n      risks<span class=\"token punctuation\">.</span><span class=\"token function\">push</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n        <span class=\"token literal-property property\">factor</span><span class=\"token operator\">:</span> <span class=\"token string\">'too_fast'</span><span class=\"token punctuation\">,</span>\n        <span class=\"token literal-property property\">severity</span><span class=\"token operator\">:</span> <span class=\"token string\">'medium'</span>\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n    \n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token literal-property property\">riskLevel</span><span class=\"token operator\">:</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">calculateOverallRisk</span><span class=\"token punctuation\">(</span>risks<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n      <span class=\"token literal-property property\">factors</span><span class=\"token operator\">:</span> risks\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>These security measures work together to create defense in depth. No single control provides complete protection, but the combination significantly raises the bar for attackers while maintaining usability for legitimate users.</p>\n<h2 id=\"magic-links-vs-other-passwordless-methods\" style=\"position:relative;\"><a href=\"#magic-links-vs-other-passwordless-methods\" aria-label=\"magic links vs other passwordless methods 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>Magic Links vs Other Passwordless Methods</h2>\n<h3 id=\"comparison-table\" style=\"position:relative;\"><a href=\"#comparison-table\" aria-label=\"comparison table 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>Comparison Table</h3>\n<p>Passwordless authentication encompasses multiple approaches, each with distinct trade-offs in security, user experience, and implementation complexity. Understanding these differences guides selection of the appropriate method for specific use cases.</p>\n<table>\n<thead>\n<tr>\n<th>Method</th>\n<th>Security Level</th>\n<th>UX Convenience</th>\n<th>Setup Complexity</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>Magic Links</strong></td>\n<td>High</td>\n<td>Very High</td>\n<td>Moderate</td>\n</tr>\n<tr>\n<td><strong>SMS/Email OTP</strong></td>\n<td>Medium</td>\n<td>Moderate</td>\n<td>Low</td>\n</tr>\n<tr>\n<td><strong>WebAuthn/Biometrics</strong></td>\n<td>Very High</td>\n<td>High</td>\n<td>High</td>\n</tr>\n<tr>\n<td><strong>Hardware Tokens</strong></td>\n<td>Very High</td>\n<td>Low</td>\n<td>Very High</td>\n</tr>\n</tbody>\n</table>\n<p><strong>Security Level Definitions:</strong></p>\n<ul>\n<li><strong>Medium</strong>: Vulnerable to SIM swapping, phishing, or interception</li>\n<li><strong>High</strong>: Resistant to most attacks, some theoretical vulnerabilities</li>\n<li><strong>Very High</strong>: Cryptographically secure, phishing-resistant</li>\n</ul>\n<h3 id=\"detailed-method-analysis\" style=\"position:relative;\"><a href=\"#detailed-method-analysis\" aria-label=\"detailed method analysis 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>Detailed Method Analysis</h3>\n<p><strong>Magic Links</strong></p>\n<p>Magic links provide high security through cryptographic tokens with limited validity windows.Implementation requires email infrastructure investment but minimal user education. The asynchronous nature suits applications with infrequent access patterns. Substack’s implementation serves 2 million daily authentications with 99.7% delivery success using SendGrid’s infrastructure.</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"68972691437536280000\"\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(`// Magic link implementation metrics\nconst magicLinkMetrics = {\n  averageDeliveryTime: 8.3, // seconds\n  expirationWindow: 900, // 15 minutes in seconds\n  clickThroughRate: 0.73,\n  costPerAuth: 0.003, // \\$0.003 per email via SendGrid\n  supportTickets: 0.02 // 2% of users need support\n};`, `68972691437536280000`)\"\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 comment\">// Magic link implementation metrics</span>\n<span class=\"token keyword\">const</span> magicLinkMetrics <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token literal-property property\">averageDeliveryTime</span><span class=\"token operator\">:</span> <span class=\"token number\">8.3</span><span class=\"token punctuation\">,</span> <span class=\"token comment\">// seconds</span>\n  <span class=\"token literal-property property\">expirationWindow</span><span class=\"token operator\">:</span> <span class=\"token number\">900</span><span class=\"token punctuation\">,</span> <span class=\"token comment\">// 15 minutes in seconds</span>\n  <span class=\"token literal-property property\">clickThroughRate</span><span class=\"token operator\">:</span> <span class=\"token number\">0.73</span><span class=\"token punctuation\">,</span>\n  <span class=\"token literal-property property\">costPerAuth</span><span class=\"token operator\">:</span> <span class=\"token number\">0.003</span><span class=\"token punctuation\">,</span> <span class=\"token comment\">// $0.003 per email via SendGrid</span>\n  <span class=\"token literal-property property\">supportTickets</span><span class=\"token operator\">:</span> <span class=\"token number\">0.02</span> <span class=\"token comment\">// 2% of users need support</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p><strong>SMS OTP</strong></p>\n<p>SMS one time passwords achieve a high success rates due to immediate delivery and familiar user experience. However, SIM swapping attacks compromised over $68 million in 2023 according to FBI IC3 reports, making SMS unsuitable for high-value accounts.</p>\n<p>Twilio’s pricing at $0.0075 per SMS makes this more expensive than email-based methods. Regulatory requirements like A2P 10DLC registration in the US add complexity. WhatsApp reduced SMS OTP usage by after implementing app-based authentication due to cost and security concerns.</p>\n<p><strong>Email OTP</strong></p>\n<p>Email OTP combines magic link security with traditional OTP user experience. Users enter a 6-digit code rather than clicking a link, addressing concerns about email client link modification. GitHub uses email OTP as a fallback when WebAuthn isn’t available..</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"92240149477960660000\"\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 secrets\nimport time\nfrom typing import Optional\n\nclass EmailOTPService:\n    OTP_LENGTH = 6\n    VALIDITY_SECONDS = 300 \n    \n    @staticmethod\n    def generate_otp() -> tuple[str, str]:\n        &quot;&quot;&quot;Generate OTP and hash for storage&quot;&quot;&quot;\n        otp = ''.join([str(secrets.randbelow(10)) for _ in range(EmailOTPService.OTP_LENGTH)])\n        # Store hash, not plain OTP\n        otp_hash = hashlib.sha256(otp.encode()).hexdigest()\n        return otp, otp_hash\n    \n    @staticmethod\n    def verify_otp(submitted_otp: str, stored_hash: str, created_at: float) -> bool:\n        &quot;&quot;&quot;Verify OTP with timing attack resistance&quot;&quot;&quot;\n        if time.time() - created_at > EmailOTPService.VALIDITY_SECONDS:\n            return False\n        \n        submitted_hash = hashlib.sha256(submitted_otp.encode()).hexdigest()\n        return secrets.compare_digest(submitted_hash, stored_hash)`, `92240149477960660000`)\"\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=\"python\"><pre class=\"language-python\"><code class=\"language-python\"><span class=\"token keyword\">import</span> secrets\n<span class=\"token keyword\">import</span> time\n<span class=\"token keyword\">from</span> typing <span class=\"token keyword\">import</span> Optional\n\n<span class=\"token keyword\">class</span> <span class=\"token class-name\">EmailOTPService</span><span class=\"token punctuation\">:</span>\n    OTP_LENGTH <span class=\"token operator\">=</span> <span class=\"token number\">6</span>\n    VALIDITY_SECONDS <span class=\"token operator\">=</span> <span class=\"token number\">300</span> \n    \n    <span class=\"token decorator annotation punctuation\">@staticmethod</span>\n    <span class=\"token keyword\">def</span> <span class=\"token function\">generate_otp</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">-</span><span class=\"token operator\">></span> <span class=\"token builtin\">tuple</span><span class=\"token punctuation\">[</span><span class=\"token builtin\">str</span><span class=\"token punctuation\">,</span> <span class=\"token builtin\">str</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">:</span>\n        <span class=\"token triple-quoted-string string\">\"\"\"Generate OTP and hash for storage\"\"\"</span>\n        otp <span class=\"token operator\">=</span> <span class=\"token string\">''</span><span class=\"token punctuation\">.</span>join<span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span><span class=\"token builtin\">str</span><span class=\"token punctuation\">(</span>secrets<span class=\"token punctuation\">.</span>randbelow<span class=\"token punctuation\">(</span><span class=\"token number\">10</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">for</span> _ <span class=\"token keyword\">in</span> <span class=\"token builtin\">range</span><span class=\"token punctuation\">(</span>EmailOTPService<span class=\"token punctuation\">.</span>OTP_LENGTH<span class=\"token punctuation\">)</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n        <span class=\"token comment\"># Store hash, not plain OTP</span>\n        otp_hash <span class=\"token operator\">=</span> hashlib<span class=\"token punctuation\">.</span>sha256<span class=\"token punctuation\">(</span>otp<span class=\"token punctuation\">.</span>encode<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>hexdigest<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n        <span class=\"token keyword\">return</span> otp<span class=\"token punctuation\">,</span> otp_hash\n    \n    <span class=\"token decorator annotation punctuation\">@staticmethod</span>\n    <span class=\"token keyword\">def</span> <span class=\"token function\">verify_otp</span><span class=\"token punctuation\">(</span>submitted_otp<span class=\"token punctuation\">:</span> <span class=\"token builtin\">str</span><span class=\"token punctuation\">,</span> stored_hash<span class=\"token punctuation\">:</span> <span class=\"token builtin\">str</span><span class=\"token punctuation\">,</span> created_at<span class=\"token punctuation\">:</span> <span class=\"token builtin\">float</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">-</span><span class=\"token operator\">></span> <span class=\"token builtin\">bool</span><span class=\"token punctuation\">:</span>\n        <span class=\"token triple-quoted-string string\">\"\"\"Verify OTP with timing attack resistance\"\"\"</span>\n        <span class=\"token keyword\">if</span> time<span class=\"token punctuation\">.</span>time<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">-</span> created_at <span class=\"token operator\">></span> EmailOTPService<span class=\"token punctuation\">.</span>VALIDITY_SECONDS<span class=\"token punctuation\">:</span>\n            <span class=\"token keyword\">return</span> <span class=\"token boolean\">False</span>\n        \n        submitted_hash <span class=\"token operator\">=</span> hashlib<span class=\"token punctuation\">.</span>sha256<span class=\"token punctuation\">(</span>submitted_otp<span class=\"token punctuation\">.</span>encode<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>hexdigest<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n        <span class=\"token keyword\">return</span> secrets<span class=\"token punctuation\">.</span>compare_digest<span class=\"token punctuation\">(</span>submitted_hash<span class=\"token punctuation\">,</span> stored_hash<span class=\"token punctuation\">)</span></code></pre></div>\n<p><strong>TOTP Apps</strong></p>\n<p>Time-based OTP applications like Google Authenticator and Authy provide offline capability and phishing resistance without per-use costs. Common TOTP failures result from time synchronization issues or users selecting the wrong account in their authenticator app.</p>\n<p>Enterprise adoption remains strong due to offline functionality. JPMorgan Chase requires TOTP for all 250,000 employees, citing zero infrastructure costs after initial deployment.</p>\n<p><strong>WebAuthn/Biometrics</strong></p>\n<p>WebAuthn achieves the highest success rate by leveraging built in device capabilities. Apple’s PassKeys adoption reached 150 million users within 18 months of launch. The implementation complexity involves certificate management and fallback mechanisms for unsupported devices.</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"65545174182434310000\"\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(`// WebAuthn implementation with fallback\nclass AuthenticationService {\n  async authenticate(username) {\n    // Check WebAuthn support\n    if (window.PublicKeyCredential) {\n      try {\n        const assertion = await navigator.credentials.get({\n          publicKey: {\n            challenge: await this.getChallenge(),\n            allowCredentials: await this.getUserCredentials(username),\n            userVerification: &quot;preferred&quot;\n          }\n        });\n        return this.verifyAssertion(assertion);\n      } catch (error) {\n        console.log('WebAuthn failed, falling back');\n      }\n    }\n    \n    // Fallback to magic link\n    return this.sendMagicLink(username);\n  }\n}`, `65545174182434310000`)\"\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 comment\">// WebAuthn implementation with fallback</span>\n<span class=\"token keyword\">class</span> <span class=\"token class-name\">AuthenticationService</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">async</span> <span class=\"token function\">authenticate</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">username</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token comment\">// Check WebAuthn support</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>window<span class=\"token punctuation\">.</span>PublicKeyCredential<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">try</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">const</span> assertion <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> navigator<span class=\"token punctuation\">.</span>credentials<span class=\"token punctuation\">.</span><span class=\"token function\">get</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n          <span class=\"token literal-property property\">publicKey</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token literal-property property\">challenge</span><span class=\"token operator\">:</span> <span class=\"token keyword\">await</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">getChallenge</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n            <span class=\"token literal-property property\">allowCredentials</span><span class=\"token operator\">:</span> <span class=\"token keyword\">await</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">getUserCredentials</span><span class=\"token punctuation\">(</span>username<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n            <span class=\"token literal-property property\">userVerification</span><span class=\"token operator\">:</span> <span class=\"token string\">\"preferred\"</span>\n          <span class=\"token punctuation\">}</span>\n        <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 keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">verifyAssertion</span><span class=\"token punctuation\">(</span>assertion<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n      <span class=\"token punctuation\">}</span> <span class=\"token keyword\">catch</span> <span class=\"token punctuation\">(</span>error<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'WebAuthn failed, falling back'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n      <span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">}</span>\n    \n    <span class=\"token comment\">// Fallback to magic link</span>\n    <span class=\"token keyword\">return</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">sendMagicLink</span><span class=\"token punctuation\">(</span>username<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p><strong>Hardware Tokens</strong></p>\n<p>Hardware security keys provide the highest security level. <a href=\"https://www.yubico.com/resources/reference-customers/google/\" target=\"_blank\" rel=\"nofollow\">Google makes use of YubiKey</a> to completely eliminate employee account takeovers.</p>\n<p>YubiKey’s 2024 report shows 4.2 million keys deployed across Fortune 500 companies, primarily in finance and healthcare sectors where regulatory compliance justifies the investment.</p>\n<p><strong>Push Notifications</strong></p>\n<p>Push authentication through mobile apps combines security with convenience, achieving a high success rates. <a href=\"https://newsroom.cisco.com/c/r/newsroom/en/us/a/y2020/m11/cisco-s-duo-security-report-finds-digital-acceleration-driven-by-unprecedented-shift-to-remote-work.html\" target=\"_blank\" rel=\"nofollow\">Duo Security</a> processes 900 million push authentications monthly with average response times of 3.7 seconds. Implementation requires mobile app development and push notification infrastructure.</p>\n<p>The method’s weakness lies in push fatigue attacks, where users approve notifications without verifying legitimacy. Uber’s 2022 breach exploited this vulnerability, leading to number-matching requirements in push authentication systems.</p>\n<h3 id=\"when-to-use-magic-links-over-others\" style=\"position:relative;\"><a href=\"#when-to-use-magic-links-over-others\" aria-label=\"when to use magic links over others 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>When to Use Magic Links Over Others</h3>\n<p>Magic links excel in specific scenarios where their characteristics align with application requirements and user behavior patterns.</p>\n<p><strong>Ideal for Apps Prioritizing Simplicity</strong></p>\n<p>Applications targeting non-technical users benefit from magic links’ minimal cognitive load. Newsletter platforms, community forums, and content subscription services report higher completion rates with magic links compared to traditional authentication.</p>\n<p><strong>Email-First Access Patterns</strong></p>\n<p>Business applications where email serves as the primary communication channel naturally suit magic link authentication. Project management tools, document collaboration platforms, and B2B SaaS applications leverage existing email workflows.</p>\n<p><strong>Low-Barrier Onboarding Requirements</strong></p>\n<p>Applications requiring minimal friction during initial user acquisition benefit significantly from magic links. E-commerce guest checkouts, event registrations, and free trial signups show improved conversion with single-field authentication.</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"41918100446942175000\"\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(`interface OnboardingMetrics {\n  passwordRegistration: {\n    formFields: number;\n    completionRate: number;\n    timeToComplete: number;\n  };\n  magicLink: {\n    formFields: number;\n    completionRate: number;\n    timeToComplete: number;\n  };\n}`, `41918100446942175000`)\"\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=\"typescript\"><pre class=\"language-typescript\"><code class=\"language-typescript\"><span class=\"token keyword\">interface</span> <span class=\"token class-name\">OnboardingMetrics</span> <span class=\"token punctuation\">{</span>\n  passwordRegistration<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n    formFields<span class=\"token operator\">:</span> <span class=\"token builtin\">number</span><span class=\"token punctuation\">;</span>\n    completionRate<span class=\"token operator\">:</span> <span class=\"token builtin\">number</span><span class=\"token punctuation\">;</span>\n    timeToComplete<span class=\"token operator\">:</span> <span class=\"token builtin\">number</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n  magicLink<span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n    formFields<span class=\"token operator\">:</span> <span class=\"token builtin\">number</span><span class=\"token punctuation\">;</span>\n    completionRate<span class=\"token operator\">:</span> <span class=\"token builtin\">number</span><span class=\"token punctuation\">;</span>\n    timeToComplete<span class=\"token operator\">:</span> <span class=\"token builtin\">number</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p><strong>Infrequent Access Applications</strong></p>\n<p>Services accessed weekly or less frequently benefit from eliminating password memory burden. Tax preparation software, annual subscription renewals, and compliance training platforms.</p>\n<p><strong>When Other Methods Excel</strong></p>\n<p>Magic links prove inappropriate for certain use cases:</p>\n<ul>\n<li><strong>High-frequency access</strong>: Trading platforms and communication tools requiring multiple daily logins frustrate users with email delays</li>\n<li><strong>Offline requirements</strong>: Point-of-sale systems and field service applications need authentication without internet connectivity</li>\n<li><strong>Regulated environments</strong>: Banking and healthcare often mandate specific authentication methods for compliance</li>\n<li><strong>High-security operations</strong>: Administrative access and financial transactions benefit from hardware token certainty</li>\n</ul>\n<p>The authentication method selection ultimately depends on balancing security requirements, user experience expectations, and implementation resources. Magic links occupy a sweet spot for many consumer and business applications, providing strong security with minimal user friction at reasonable implementation cost.</p>\n<h2 id=\"how-supertokens-simplifies-magic-link-integration\" style=\"position:relative;\"><a href=\"#how-supertokens-simplifies-magic-link-integration\" aria-label=\"how supertokens simplifies magic link integration 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 Magic Link Integration</h2>\n<h3 id=\"built-in-passwordless-recipe\" style=\"position:relative;\"><a href=\"#built-in-passwordless-recipe\" aria-label=\"built in passwordless recipe 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>Built-In Passwordless Recipe</h3>\n<p>SuperTokens provides a complete passwordless authentication system through its Passwordless Recipe, eliminating the need to build token generation, validation, and session management from scratch. The implementation handles all security considerations while exposing simple APIs for integration.</p>\n<p>The core <code class=\"language-text\">/auth/signinup/code</code> endpoint manages the entire magic link flow automatically. When users submit their email, SuperTokens generates cryptographically secure tokens, stores them with appropriate metadata, and handles email delivery. The same endpoint validates tokens when users click the magic link, creating sessions without additional backend code.</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"50476864619895380000\"\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-node&quot;;\nimport Passwordless from &quot;supertokens-node/recipe/passwordless&quot;;\nimport Session from &quot;supertokens-node/recipe/session&quot;;\n\nSuperTokens.init({\n  appInfo: {\n    apiDomain: &quot;http://localhost:3001&quot;,\n    appName: &quot;MyApp&quot;,\n    websiteDomain: &quot;http://localhost:3000&quot;\n  },\n  recipeList: [\n    Passwordless.init({\n      flowType: &quot;MAGIC_LINK&quot;,\n      contactMethod: &quot;EMAIL&quot;\n    }),\n    Session.init()\n  ]\n});\n\n// SuperTokens now handles:\n// - POST /auth/signinup/code sends magic link\n// - POST /auth/signinup/code/consume validates token\n// - All session management endpoints`, `50476864619895380000`)\"\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-node\"</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">import</span> Passwordless <span class=\"token keyword\">from</span> <span class=\"token string\">\"supertokens-node/recipe/passwordless\"</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\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\">apiDomain</span><span class=\"token operator\">:</span> <span class=\"token string\">\"http://localhost:3001\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">appName</span><span class=\"token operator\">:</span> <span class=\"token string\">\"MyApp\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">websiteDomain</span><span class=\"token operator\">:</span> <span class=\"token string\">\"http://localhost:3000\"</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    Passwordless<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\">flowType</span><span class=\"token operator\">:</span> <span class=\"token string\">\"MAGIC_LINK\"</span><span class=\"token punctuation\">,</span>\n      <span class=\"token literal-property property\">contactMethod</span><span class=\"token operator\">:</span> <span class=\"token string\">\"EMAIL\"</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>\n\n<span class=\"token comment\">// SuperTokens now handles:</span>\n<span class=\"token comment\">// - POST /auth/signinup/code sends magic link</span>\n<span class=\"token comment\">// - POST /auth/signinup/code/consume validates token</span>\n<span class=\"token comment\">// - All session management endpoints</span></code></pre></div>\n<p>The Passwordless Recipe supports three flow types: <code class=\"language-text\">MAGIC_LINK</code> for link only authentication, <code class=\"language-text\">USER_INPUT_CODE</code> for OTP only, and <code class=\"language-text\">USER_INPUT_CODE_AND_MAGIC_LINK</code> for maximum flexibility. Each flow automatically configures the appropriate endpoints and validation logic.</p>\n<p>Frontend integration requires minimal code with the pre-built UI components:</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"46036751553247494000\"\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 Passwordless from &quot;supertokens-auth-react/recipe/passwordless&quot;;\n\nSuperTokens.init({\n  appInfo: {\n    apiDomain: &quot;http://localhost:3001&quot;,\n    appName: &quot;MyApp&quot;,\n    websiteDomain: &quot;http://localhost:3000&quot;,\n    apiBasePath: &quot;/auth&quot;,\n    websiteBasePath: &quot;/auth&quot;\n  },\n  recipeList: [\n    Passwordless.init({\n      contactMethod: &quot;EMAIL&quot;\n    })\n  ]\n});\n\n// SuperTokens automatically provides:\n// - Email input form at /auth\n// - Link verification page at /auth/verify\n// - Session management across all pages`, `46036751553247494000`)\"\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> Passwordless <span class=\"token keyword\">from</span> <span class=\"token string\">\"supertokens-auth-react/recipe/passwordless\"</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\">apiDomain</span><span class=\"token operator\">:</span> <span class=\"token string\">\"http://localhost:3001\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">appName</span><span class=\"token operator\">:</span> <span class=\"token string\">\"MyApp\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">websiteDomain</span><span class=\"token operator\">:</span> <span class=\"token string\">\"http://localhost:3000\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">apiBasePath</span><span class=\"token operator\">:</span> <span class=\"token string\">\"/auth\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">websiteBasePath</span><span class=\"token operator\">:</span> <span class=\"token string\">\"/auth\"</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    Passwordless<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\">contactMethod</span><span class=\"token operator\">:</span> <span class=\"token string\">\"EMAIL\"</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><span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\">// SuperTokens automatically provides:</span>\n<span class=\"token comment\">// - Email input form at /auth</span>\n<span class=\"token comment\">// - Link verification page at /auth/verify</span>\n<span class=\"token comment\">// - Session management across all pages</span></code></pre></div>\n<h3 id=\"customizable-flows\" style=\"position:relative;\"><a href=\"#customizable-flows\" aria-label=\"customizable 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>Customizable Flows</h3>\n<p>SuperTokens recognizes that production applications require flexibility beyond default implementations. The override pattern enables customization of every aspect while maintaining security guarantees.</p>\n<p><strong>Link Formatting and Domain Customization</strong></p>\n<p>Organizations often need magic links pointing to custom domains or specific paths. SuperTokens provides multiple customization points:</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"79577091305327260000\"\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(`from supertokens_python import init, InputAppInfo\nfrom supertokens_python.recipe import passwordless\nfrom supertokens_python.recipe.passwordless.types import EmailDeliveryOverrideInput, EmailTemplateVars\n\ndef custom_email_deliver(original_implementation: EmailDeliveryOverrideInput) -> EmailDeliveryOverrideInput:\n    original_send_email = original_implementation.send_email\n    \n    async def send_email(template_vars: EmailTemplateVars, user_context):\n        # Customize the magic link URL\n        if template_vars.url_with_link_code:\n            # Replace default domain with custom domain\n            template_vars.url_with_link_code = template_vars.url_with_link_code.replace(\n                &quot;http://localhost:3000/auth/verify&quot;,\n                &quot;https://login.mycompany.com/authenticate&quot;\n            )\n            \n            # Add UTM parameters for analytics\n            template_vars.url_with_link_code += &quot;&utm_source=email&utm_campaign=login&quot;\n        \n        # Customize email content\n        template_vars.email = {\n            &quot;subject&quot;: &quot;Your secure login link&quot;,\n            &quot;html&quot;: f&quot;&quot;&quot;\n                <h2>Welcome back!</h2>\n                <p>Click below to access your account:</p>\n                <a href=&quot;{template_vars.url_with_link_code}&quot;>\n                    Login to Dashboard\n                </a>\n                <p>Link expires in 15 minutes</p>\n            &quot;&quot;&quot;,\n            &quot;text&quot;: f&quot;Login here: {template_vars.url_with_link_code}&quot;\n        }\n        \n        return await original_send_email(template_vars, user_context)\n    \n    original_implementation.send_email = send_email\n    return original_implementation\n\ninit(\n    app_info=InputAppInfo(\n        api_domain=&quot;https://api.mycompany.com&quot;,\n        app_name=&quot;MyCompany&quot;,\n        website_domain=&quot;https://mycompany.com&quot;\n    ),\n    recipe_list=[\n        passwordless.init(\n            flow_type=&quot;MAGIC_LINK&quot;,\n            contact_method=&quot;EMAIL&quot;,\n            email_delivery=passwordless.EmailDeliveryConfig(\n                override=custom_email_deliver\n            )\n        )\n    ]\n)`, `79577091305327260000`)\"\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=\"python\"><pre class=\"language-python\"><code class=\"language-python\"><span class=\"token keyword\">from</span> supertokens_python <span class=\"token keyword\">import</span> init<span class=\"token punctuation\">,</span> InputAppInfo\n<span class=\"token keyword\">from</span> supertokens_python<span class=\"token punctuation\">.</span>recipe <span class=\"token keyword\">import</span> passwordless\n<span class=\"token keyword\">from</span> supertokens_python<span class=\"token punctuation\">.</span>recipe<span class=\"token punctuation\">.</span>passwordless<span class=\"token punctuation\">.</span>types <span class=\"token keyword\">import</span> EmailDeliveryOverrideInput<span class=\"token punctuation\">,</span> EmailTemplateVars\n\n<span class=\"token keyword\">def</span> <span class=\"token function\">custom_email_deliver</span><span class=\"token punctuation\">(</span>original_implementation<span class=\"token punctuation\">:</span> EmailDeliveryOverrideInput<span class=\"token punctuation\">)</span> <span class=\"token operator\">-</span><span class=\"token operator\">></span> EmailDeliveryOverrideInput<span class=\"token punctuation\">:</span>\n    original_send_email <span class=\"token operator\">=</span> original_implementation<span class=\"token punctuation\">.</span>send_email\n    \n    <span class=\"token keyword\">async</span> <span class=\"token keyword\">def</span> <span class=\"token function\">send_email</span><span class=\"token punctuation\">(</span>template_vars<span class=\"token punctuation\">:</span> EmailTemplateVars<span class=\"token punctuation\">,</span> user_context<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n        <span class=\"token comment\"># Customize the magic link URL</span>\n        <span class=\"token keyword\">if</span> template_vars<span class=\"token punctuation\">.</span>url_with_link_code<span class=\"token punctuation\">:</span>\n            <span class=\"token comment\"># Replace default domain with custom domain</span>\n            template_vars<span class=\"token punctuation\">.</span>url_with_link_code <span class=\"token operator\">=</span> template_vars<span class=\"token punctuation\">.</span>url_with_link_code<span class=\"token punctuation\">.</span>replace<span class=\"token punctuation\">(</span>\n                <span class=\"token string\">\"http://localhost:3000/auth/verify\"</span><span class=\"token punctuation\">,</span>\n                <span class=\"token string\">\"https://login.mycompany.com/authenticate\"</span>\n            <span class=\"token punctuation\">)</span>\n            \n            <span class=\"token comment\"># Add UTM parameters for analytics</span>\n            template_vars<span class=\"token punctuation\">.</span>url_with_link_code <span class=\"token operator\">+=</span> <span class=\"token string\">\"&amp;utm_source=email&amp;utm_campaign=login\"</span>\n        \n        <span class=\"token comment\"># Customize email content</span>\n        template_vars<span class=\"token punctuation\">.</span>email <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token string\">\"subject\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"Your secure login link\"</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">\"html\"</span><span class=\"token punctuation\">:</span> <span class=\"token string-interpolation\"><span class=\"token string\">f\"\"\"\n                &lt;h2>Welcome back!&lt;/h2>\n                &lt;p>Click below to access your account:&lt;/p>\n                &lt;a href=\"</span><span class=\"token interpolation\"><span class=\"token punctuation\">{</span>template_vars<span class=\"token punctuation\">.</span>url_with_link_code<span class=\"token punctuation\">}</span></span><span class=\"token string\">\">\n                    Login to Dashboard\n                &lt;/a>\n                &lt;p>Link expires in 15 minutes&lt;/p>\n            \"\"\"</span></span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">\"text\"</span><span class=\"token punctuation\">:</span> <span class=\"token string-interpolation\"><span class=\"token string\">f\"Login here: </span><span class=\"token interpolation\"><span class=\"token punctuation\">{</span>template_vars<span class=\"token punctuation\">.</span>url_with_link_code<span class=\"token punctuation\">}</span></span><span class=\"token string\">\"</span></span>\n        <span class=\"token punctuation\">}</span>\n        \n        <span class=\"token keyword\">return</span> <span class=\"token keyword\">await</span> original_send_email<span class=\"token punctuation\">(</span>template_vars<span class=\"token punctuation\">,</span> user_context<span class=\"token punctuation\">)</span>\n    \n    original_implementation<span class=\"token punctuation\">.</span>send_email <span class=\"token operator\">=</span> send_email\n    <span class=\"token keyword\">return</span> original_implementation\n\ninit<span class=\"token punctuation\">(</span>\n    app_info<span class=\"token operator\">=</span>InputAppInfo<span class=\"token punctuation\">(</span>\n        api_domain<span class=\"token operator\">=</span><span class=\"token string\">\"https://api.mycompany.com\"</span><span class=\"token punctuation\">,</span>\n        app_name<span class=\"token operator\">=</span><span class=\"token string\">\"MyCompany\"</span><span class=\"token punctuation\">,</span>\n        website_domain<span class=\"token operator\">=</span><span class=\"token string\">\"https://mycompany.com\"</span>\n    <span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n    recipe_list<span class=\"token operator\">=</span><span class=\"token punctuation\">[</span>\n        passwordless<span class=\"token punctuation\">.</span>init<span class=\"token punctuation\">(</span>\n            flow_type<span class=\"token operator\">=</span><span class=\"token string\">\"MAGIC_LINK\"</span><span class=\"token punctuation\">,</span>\n            contact_method<span class=\"token operator\">=</span><span class=\"token string\">\"EMAIL\"</span><span class=\"token punctuation\">,</span>\n            email_delivery<span class=\"token operator\">=</span>passwordless<span class=\"token punctuation\">.</span>EmailDeliveryConfig<span class=\"token punctuation\">(</span>\n                override<span class=\"token operator\">=</span>custom_email_deliver\n            <span class=\"token punctuation\">)</span>\n        <span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">]</span>\n<span class=\"token punctuation\">)</span></code></pre></div>\n<p><strong>Expiry Logic Configuration</strong></p>\n<p>Token lifetime adjustments require only configuration changes, not code modifications. SuperTokens defaults to 900000ms (15 minutes) but supports any duration:</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"78577631305595220000\"\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(`// Using Docker\ndocker run \\\n  -p 3567:3567 \\\n  -e PASSWORDLESS_CODE_LIFETIME=300000 \\  // 5 minutes\n  -d registry.supertokens.io/supertokens/supertokens-postgresql\n\n// Using config.yaml\npasswordless_code_lifetime: 1800000  // 30 minutes\n\n// For managed service configure via dashboard`, `78577631305595220000`)\"\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 comment\">// Using Docker</span>\ndocker run \\\n  <span class=\"token operator\">-</span>p <span class=\"token number\">3567</span><span class=\"token operator\">:</span><span class=\"token number\">3567</span> \\\n  <span class=\"token operator\">-</span>e <span class=\"token constant\">PASSWORDLESS_CODE_LIFETIME</span><span class=\"token operator\">=</span><span class=\"token number\">300000</span> \\  <span class=\"token comment\">// 5 minutes</span>\n  <span class=\"token operator\">-</span>d registry<span class=\"token punctuation\">.</span>supertokens<span class=\"token punctuation\">.</span>io<span class=\"token operator\">/</span>supertokens<span class=\"token operator\">/</span>supertokens<span class=\"token operator\">-</span>postgresql\n\n<span class=\"token comment\">// Using config.yaml</span>\n<span class=\"token literal-property property\">passwordless_code_lifetime</span><span class=\"token operator\">:</span> <span class=\"token number\">1800000</span>  <span class=\"token comment\">// 30 minutes</span>\n\n<span class=\"token comment\">// For managed service configure via dashboard</span></code></pre></div>\n<p><strong>Email Delivery Integration</strong></p>\n<p>SuperTokens integrates with any email provider through its flexible delivery system:</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"91133760466331800000\"\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 { TwilioService } from &quot;supertokens-node/recipe/passwordless/emaildelivery&quot;;\nimport nodemailer from &quot;nodemailer&quot;;\n\nPasswordless.init({\n  emailDelivery: {\n    service: new TwilioService({\n      twilioSettings: {\n        accountSid: process.env.TWILIO_ACCOUNT_SID,\n        authToken: process.env.TWILIO_AUTH_TOKEN,\n        from: process.env.TWILIO_FROM_EMAIL\n      }\n    })\n  }\n});\n\n// Or use custom SMTP\nconst transporter = nodemailer.createTransporter({\n  host: &quot;smtp.sendgrid.net&quot;,\n  port: 587,\n  auth: {\n    user: &quot;apikey&quot;,\n    pass: process.env.SENDGRID_API_KEY\n  }\n});\n\nPasswordless.init({\n  emailDelivery: {\n    override: (originalImplementation) => ({\n      sendEmail: async (input) => {\n        await transporter.sendMail({\n          from: &quot;noreply@mycompany.com&quot;,\n          to: input.email,\n          subject: &quot;Your login link&quot;,\n          html: input.emailContent\n        });\n      }\n    })\n  }\n});`, `91133760466331800000`)\"\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> TwilioService <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">\"supertokens-node/recipe/passwordless/emaildelivery\"</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">import</span> nodemailer <span class=\"token keyword\">from</span> <span class=\"token string\">\"nodemailer\"</span><span class=\"token punctuation\">;</span>\n\nPasswordless<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\">emailDelivery</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token literal-property property\">service</span><span class=\"token operator\">:</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">TwilioService</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n      <span class=\"token literal-property property\">twilioSettings</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token literal-property property\">accountSid</span><span class=\"token operator\">:</span> process<span class=\"token punctuation\">.</span>env<span class=\"token punctuation\">.</span><span class=\"token constant\">TWILIO_ACCOUNT_SID</span><span class=\"token punctuation\">,</span>\n        <span class=\"token literal-property property\">authToken</span><span class=\"token operator\">:</span> process<span class=\"token punctuation\">.</span>env<span class=\"token punctuation\">.</span><span class=\"token constant\">TWILIO_AUTH_TOKEN</span><span class=\"token punctuation\">,</span>\n        <span class=\"token literal-property property\">from</span><span class=\"token operator\">:</span> process<span class=\"token punctuation\">.</span>env<span class=\"token punctuation\">.</span><span class=\"token constant\">TWILIO_FROM_EMAIL</span>\n      <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><span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\">// Or use custom SMTP</span>\n<span class=\"token keyword\">const</span> transporter <span class=\"token operator\">=</span> nodemailer<span class=\"token punctuation\">.</span><span class=\"token function\">createTransporter</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n  <span class=\"token literal-property property\">host</span><span class=\"token operator\">:</span> <span class=\"token string\">\"smtp.sendgrid.net\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token literal-property property\">port</span><span class=\"token operator\">:</span> <span class=\"token number\">587</span><span class=\"token punctuation\">,</span>\n  <span class=\"token literal-property property\">auth</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token literal-property property\">user</span><span class=\"token operator\">:</span> <span class=\"token string\">\"apikey\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">pass</span><span class=\"token operator\">:</span> process<span class=\"token punctuation\">.</span>env<span class=\"token punctuation\">.</span><span class=\"token constant\">SENDGRID_API_KEY</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\nPasswordless<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\">emailDelivery</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token function-variable function\">override</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">originalImplementation</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n      <span class=\"token function-variable function\">sendEmail</span><span class=\"token operator\">:</span> <span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">input</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">await</span> transporter<span class=\"token punctuation\">.</span><span class=\"token function\">sendMail</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n          <span class=\"token literal-property property\">from</span><span class=\"token operator\">:</span> <span class=\"token string\">\"noreply@mycompany.com\"</span><span class=\"token punctuation\">,</span>\n          <span class=\"token literal-property property\">to</span><span class=\"token operator\">:</span> input<span class=\"token punctuation\">.</span>email<span class=\"token punctuation\">,</span>\n          <span class=\"token literal-property property\">subject</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Your login link\"</span><span class=\"token punctuation\">,</span>\n          <span class=\"token literal-property property\">html</span><span class=\"token operator\">:</span> input<span class=\"token punctuation\">.</span>emailContent\n        <span class=\"token punctuation\">}</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>\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<h3 id=\"security-and-scalability\" style=\"position:relative;\"><a href=\"#security-and-scalability\" aria-label=\"security and scalability 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 and Scalability</h3>\n<p>SuperTokens implements enterprise grade security measures that would require significant development effort to replicate.</p>\n<p><strong>In-Built Protection Against Replay Attacks</strong></p>\n<p>Each magic link token works exactly once. SuperTokens uses database level constraints to guarantee single-use enforcement:</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"49782423632258270000\"\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(`// Manual token generation with built in security\nimport Passwordless from &quot;supertokens-node/recipe/passwordless&quot;;\n\nasync function createSecureMagicLink(email: string, tenantId: string) {\n  // SuperTokens handles:\n  // - Cryptographically secure token generation\n  // - Database storage with atomic operations\n  // - Automatic expiration enforcement\n  // - Single use guarantee\n  \n  const magicLink = await Passwordless.createMagicLink({\n    email,\n    tenantId,\n    userContext: {\n      source: &quot;admin_dashboard&quot;,\n      ipAddress: request.ip\n    }\n  });\n  \n  // Link includes all security measures automatically\n  return magicLink;\n}\n\n// Token consumption is atomic - prevents race conditions\nconst consumeResult = await Passwordless.consumeCode({\n  preAuthSessionId,\n  linkCode,\n  deviceId,\n  userInputCode\n});\n\nif (consumeResult.status === &quot;OK&quot;) {\n  // Token was valid and is now invalidated\n  // User is authenticated\n} else if (consumeResult.status === &quot;RESTART_FLOW_ERROR&quot;) {\n  // Token expired or already used\n}`, `49782423632258270000`)\"\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 comment\">// Manual token generation with built in security</span>\n<span class=\"token keyword\">import</span> Passwordless <span class=\"token keyword\">from</span> <span class=\"token string\">\"supertokens-node/recipe/passwordless\"</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">async</span> <span class=\"token keyword\">function</span> <span class=\"token function\">createSecureMagicLink</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token literal-property property\">email</span><span class=\"token operator\">:</span> string<span class=\"token punctuation\">,</span> <span class=\"token literal-property property\">tenantId</span><span class=\"token operator\">:</span> string</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token comment\">// SuperTokens handles:</span>\n  <span class=\"token comment\">// - Cryptographically secure token generation</span>\n  <span class=\"token comment\">// - Database storage with atomic operations</span>\n  <span class=\"token comment\">// - Automatic expiration enforcement</span>\n  <span class=\"token comment\">// - Single use guarantee</span>\n  \n  <span class=\"token keyword\">const</span> magicLink <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> Passwordless<span class=\"token punctuation\">.</span><span class=\"token function\">createMagicLink</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n    email<span class=\"token punctuation\">,</span>\n    tenantId<span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">userContext</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token literal-property property\">source</span><span class=\"token operator\">:</span> <span class=\"token string\">\"admin_dashboard\"</span><span class=\"token punctuation\">,</span>\n      <span class=\"token literal-property property\">ipAddress</span><span class=\"token operator\">:</span> request<span class=\"token punctuation\">.</span>ip\n    <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\">// Link includes all security measures automatically</span>\n  <span class=\"token keyword\">return</span> magicLink<span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token comment\">// Token consumption is atomic - prevents race conditions</span>\n<span class=\"token keyword\">const</span> consumeResult <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> Passwordless<span class=\"token punctuation\">.</span><span class=\"token function\">consumeCode</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n  preAuthSessionId<span class=\"token punctuation\">,</span>\n  linkCode<span class=\"token punctuation\">,</span>\n  deviceId<span class=\"token punctuation\">,</span>\n  userInputCode\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>consumeResult<span class=\"token punctuation\">.</span>status <span class=\"token operator\">===</span> <span class=\"token string\">\"OK\"</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token comment\">// Token was valid and is now invalidated</span>\n  <span class=\"token comment\">// User is authenticated</span>\n<span class=\"token punctuation\">}</span> <span class=\"token keyword\">else</span> <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>consumeResult<span class=\"token punctuation\">.</span>status <span class=\"token operator\">===</span> <span class=\"token string\">\"RESTART_FLOW_ERROR\"</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token comment\">// Token expired or already used</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p><strong>Designed for Multi-Tenant and High-Scale Environments</strong></p>\n<p>SuperTokens supports multi-tenancy natively, enabling SaaS applications to isolate authentication per customer:</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"99079721215942640000\"\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(`// Multi-tenant configuration\nimport Multitenancy from &quot;supertokens-node/recipe/multitenancy&quot;;\n\nSuperTokens.init({\n  recipeList: [\n    Multitenancy.init(),\n    Passwordless.init({\n      // Magic links automatically include tenant context\n      getCustomUserInputCode: async (tenantId) => {\n        // Custom OTP per tenant if needed\n        return generateTenantSpecificOTP(tenantId);\n      }\n    })\n  ]\n});\n\n// Generate tenant specific magic link\nconst tenantMagicLink = await Passwordless.createMagicLink({\n  email: &quot;user@customer.com&quot;,\n  tenantId: &quot;customer-123&quot;  // Link bound to specific tenant\n});\n\n// Links automatically route to correct tenant\n// https://auth.myapp.com/auth/verify?token=xxx&tenantId=customer-123`, `99079721215942640000`)\"\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 comment\">// Multi-tenant configuration</span>\n<span class=\"token keyword\">import</span> Multitenancy <span class=\"token keyword\">from</span> <span class=\"token string\">\"supertokens-node/recipe/multitenancy\"</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\">recipeList</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>\n    Multitenancy<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    Passwordless<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 comment\">// Magic links automatically include tenant context</span>\n      <span class=\"token function-variable function\">getCustomUserInputCode</span><span class=\"token operator\">:</span> <span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">tenantId</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n        <span class=\"token comment\">// Custom OTP per tenant if needed</span>\n        <span class=\"token keyword\">return</span> <span class=\"token function\">generateTenantSpecificOTP</span><span class=\"token punctuation\">(</span>tenantId<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>\n  <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\">// Generate tenant specific magic link</span>\n<span class=\"token keyword\">const</span> tenantMagicLink <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> Passwordless<span class=\"token punctuation\">.</span><span class=\"token function\">createMagicLink</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n  <span class=\"token literal-property property\">email</span><span class=\"token operator\">:</span> <span class=\"token string\">\"user@customer.com\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token literal-property property\">tenantId</span><span class=\"token operator\">:</span> <span class=\"token string\">\"customer-123\"</span>  <span class=\"token comment\">// Link bound to specific tenant</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\">// Links automatically route to correct tenant</span>\n<span class=\"token comment\">// https://auth.myapp.com/auth/verify?token=xxx&amp;tenantId=customer-123</span></code></pre></div>\n<p>The architecture scales horizontally without code changes. SuperTokens Core handles millions of authentications with consistent sub-100ms response times.</p>\n<p><strong>Advanced Security Features</strong></p>\n<p>SuperTokens includes security measures often overlooked in custom implementations:</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"23046895574549553000\"\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(`Passwordless.init({\n  createAndSendCustomEmail: async (input) => {\n    // Built in rate limiting per email\n    if (input.attemptsCount > 3) {\n      // Exponential backoff automatically applied\n      throw new Error(&quot;Too many attempts&quot;);\n    }\n  },\n  \n  // Device fingerprinting\n  override: {\n    apis: (originalImplementation) => ({\n      ...originalImplementation,\n      consumeCodePOST: async (input) => {\n        // Access device/browser fingerprint\n        const deviceId = input.deviceId;\n        const userContext = input.userContext;\n        \n        // Perform additional verification\n        if (await isHighRiskDevice(deviceId)) {\n          // Require additional verification\n          return {\n            status: &quot;GENERAL_ERROR&quot;,\n            message: &quot;Additional verification required&quot;\n          };\n        }\n        \n        return originalImplementation.consumeCodePOST(input);\n      }\n    })\n  }\n});`, `23046895574549553000`)\"\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\">Passwordless<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 function-variable function\">createAndSendCustomEmail</span><span class=\"token operator\">:</span> <span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">input</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token comment\">// Built in rate limiting per email</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>input<span class=\"token punctuation\">.</span>attemptsCount <span class=\"token operator\">></span> <span class=\"token number\">3</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token comment\">// Exponential backoff automatically applied</span>\n      <span class=\"token keyword\">throw</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Error</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"Too many attempts\"</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>\n  \n  <span class=\"token comment\">// Device fingerprinting</span>\n  <span class=\"token literal-property property\">override</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token function-variable function\">apis</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">originalImplementation</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n      <span class=\"token operator\">...</span>originalImplementation<span class=\"token punctuation\">,</span>\n      <span class=\"token function-variable function\">consumeCodePOST</span><span class=\"token operator\">:</span> <span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">input</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n        <span class=\"token comment\">// Access device/browser fingerprint</span>\n        <span class=\"token keyword\">const</span> deviceId <span class=\"token operator\">=</span> input<span class=\"token punctuation\">.</span>deviceId<span class=\"token punctuation\">;</span>\n        <span class=\"token keyword\">const</span> userContext <span class=\"token operator\">=</span> input<span class=\"token punctuation\">.</span>userContext<span class=\"token punctuation\">;</span>\n        \n        <span class=\"token comment\">// Perform additional verification</span>\n        <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">await</span> <span class=\"token function\">isHighRiskDevice</span><span class=\"token punctuation\">(</span>deviceId<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n          <span class=\"token comment\">// Require additional verification</span>\n          <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token literal-property property\">status</span><span class=\"token operator\">:</span> <span class=\"token string\">\"GENERAL_ERROR\"</span><span class=\"token punctuation\">,</span>\n            <span class=\"token literal-property property\">message</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Additional verification required\"</span>\n          <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span>\n        \n        <span class=\"token keyword\">return</span> originalImplementation<span class=\"token punctuation\">.</span><span class=\"token function\">consumeCodePOST</span><span class=\"token punctuation\">(</span>input<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>\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>Session Management Integration</strong></p>\n<p>SuperTokens automatically creates secure sessions after magic link verification:</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"96425046794613390000\"\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(`// Sessions created automatically with magic links include:\n// - Secure, httpOnly cookies\n// - CSRF protection\n// - Automatic token rotation\n// - Cross-domain support\n\nSession.init({\n  cookieSameSite: &quot;lax&quot;,\n  cookieSecure: true,\n  sessionExpiredStatusCode: 401,\n  \n  // Anti-CSRF measures\n  antiCsrf: &quot;VIA_TOKEN&quot;,\n  \n  // Automatic session extension\n  refreshTokenPath: &quot;/auth/session/refresh&quot;,\n  \n  override: {\n    functions: (originalImplementation) => ({\n      ...originalImplementation,\n      createNewSession: async (input) => {\n        // Add custom claims for magic link users\n        if (input.authMethod === &quot;passwordless&quot;) {\n          input.sessionDataInJWT = {\n            ...input.sessionDataInJWT,\n            authMethod: &quot;magic_link&quot;,\n            loginTimestamp: Date.now()\n          };\n        }\n        return originalImplementation.createNewSession(input);\n      }\n    })\n  }\n});`, `96425046794613390000`)\"\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 comment\">// Sessions created automatically with magic links include:</span>\n<span class=\"token comment\">// - Secure, httpOnly cookies</span>\n<span class=\"token comment\">// - CSRF protection</span>\n<span class=\"token comment\">// - Automatic token rotation</span>\n<span class=\"token comment\">// - Cross-domain support</span>\n\nSession<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\">cookieSameSite</span><span class=\"token operator\">:</span> <span class=\"token string\">\"lax\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token literal-property property\">cookieSecure</span><span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span>\n  <span class=\"token literal-property property\">sessionExpiredStatusCode</span><span class=\"token operator\">:</span> <span class=\"token number\">401</span><span class=\"token punctuation\">,</span>\n  \n  <span class=\"token comment\">// Anti-CSRF measures</span>\n  <span class=\"token literal-property property\">antiCsrf</span><span class=\"token operator\">:</span> <span class=\"token string\">\"VIA_TOKEN\"</span><span class=\"token punctuation\">,</span>\n  \n  <span class=\"token comment\">// Automatic session extension</span>\n  <span class=\"token literal-property property\">refreshTokenPath</span><span class=\"token operator\">:</span> <span class=\"token string\">\"/auth/session/refresh\"</span><span class=\"token punctuation\">,</span>\n  \n  <span class=\"token literal-property property\">override</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token function-variable function\">functions</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">originalImplementation</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n      <span class=\"token operator\">...</span>originalImplementation<span class=\"token punctuation\">,</span>\n      <span class=\"token function-variable function\">createNewSession</span><span class=\"token operator\">:</span> <span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">input</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n        <span class=\"token comment\">// Add custom claims for magic link users</span>\n        <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>input<span class=\"token punctuation\">.</span>authMethod <span class=\"token operator\">===</span> <span class=\"token string\">\"passwordless\"</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n          input<span class=\"token punctuation\">.</span>sessionDataInJWT <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token operator\">...</span>input<span class=\"token punctuation\">.</span>sessionDataInJWT<span class=\"token punctuation\">,</span>\n            <span class=\"token literal-property property\">authMethod</span><span class=\"token operator\">:</span> <span class=\"token string\">\"magic_link\"</span><span class=\"token punctuation\">,</span>\n            <span class=\"token literal-property property\">loginTimestamp</span><span class=\"token operator\">:</span> Date<span class=\"token punctuation\">.</span><span class=\"token function\">now</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 keyword\">return</span> originalImplementation<span class=\"token punctuation\">.</span><span class=\"token function\">createNewSession</span><span class=\"token punctuation\">(</span>input<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>\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<h3 id=\"documentation-reference\" style=\"position:relative;\"><a href=\"#documentation-reference\" aria-label=\"documentation reference 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>Documentation Reference</h3>\n<p>SuperTokens provides comprehensive documentation for passwordless implementation:</p>\n<ul>\n<li><strong><a href=\"https://supertokens.com/docs/authentication/passwordless/introduction\" target=\"_blank\" rel=\"nofollow\">Passwordless Recipe Introduction</a></strong> - Complete overview and quick start guide</li>\n<li><strong><a href=\"https://supertokens.com/docs/authentication/passwordless/customize-the-magic-link\" target=\"_blank\" rel=\"nofollow\">Magic Link Customization</a></strong> - Advanced customization options</li>\n<li><strong><a href=\"https://supertokens.com/docs/authentication/passwordless/configure-email-and-sms-behavior\" target=\"_blank\" rel=\"nofollow\">Email Delivery Configuration</a></strong> - Integration with email providers</li>\n<li><strong><a href=\"https://supertokens.com/docs/multitenancy/introduction\" target=\"_blank\" rel=\"nofollow\">Multi-Tenancy Support</a></strong> - Enterprise multi-tenant configurations</li>\n<li><strong><a href=\"https://supertokens.com/docs/session/introduction\" target=\"_blank\" rel=\"nofollow\">Session Management</a></strong> - Secure session handling after authentication</li>\n</ul>\n<p>The documentation includes framework specific guides for Node.js, Python, and Go backends, plus React, Angular, and Vue frontends. Each guide provides complete, runnable code examples tested against the latest SuperTokens versions.</p>\n<p>By leveraging SuperTokens’ Passwordless Recipe, developers skip months of authentication development while gaining enterprise grade security and scalability. The implementation time drops from weeks to hours, with the confidence that edge cases, security vulnerabilities, and scaling challenges are already solved.</p>\n<h2 id=\"common-implementation-challenges\" style=\"position:relative;\"><a href=\"#common-implementation-challenges\" aria-label=\"common implementation challenges 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 Implementation Challenges</h2>\n<h3 id=\"email-deliverability\" style=\"position:relative;\"><a href=\"#email-deliverability\" aria-label=\"email deliverability 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>Email Deliverability</h3>\n<p>Email deliverability determines whether magic links reach users at all. Production systems face a harsh reality, without proper configuration, unauthenticated transactional emails land in spam folders.</p>\n<p><strong>Use Verified Domains and SPF/DKIM to Reduce Spam Filtering</strong></p>\n<p>Three DNS records form the foundation of email authentication: SPF, DKIM, and DMARC. These protocols work together to prove your emails are legitimate and should reach the inbox.</p>\n<p>SPF (Sender Policy Framework) tells receiving servers which IP addresses can send email for your domain. A typical SPF record looks like: <code class=\"language-text\">v=spf1 include:_spf.sendgrid.net ~all</code>. This simple line authorizes SendGrid to send on your behalf while soft-failing others.</p>\n<p>DKIM (DomainKeys Identified Mail) adds a cryptographic signature to every email, proving it hasn’t been tampered with during transit. The receiving server checks this signature against a public key in your DNS records. Modern email providers handle DKIM signing automatically, but you must add their public key to your DNS.</p>\n<p>DMARC builds on SPF and DKIM to specify what happens when authentication fails. Start with monitoring mode (<code class=\"language-text\">p=none</code>) to understand your email ecosystem, then gradually move to quarantine or reject policies. Shopify improved their merchant notification deliverability from 82% to 97% after implementing all three protocols.</p>\n<p>Common deliverability issues and solutions:</p>\n<table>\n<thead>\n<tr>\n<th>Issue</th>\n<th>Impact</th>\n<th>Solution</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>IP Warming</td>\n<td>New IPs blocked</td>\n<td>Gradually increase volume over 4-6 weeks</td>\n</tr>\n<tr>\n<td>Shared IP Reputation</td>\n<td>spam rate increase</td>\n<td>Use dedicated IPs for >100k emails/month</td>\n</tr>\n<tr>\n<td>Content Filtering</td>\n<td>false positives</td>\n<td>Avoid spam trigger words, balanced text/image ratio</td>\n</tr>\n<tr>\n<td>List Hygiene</td>\n<td>bounce rate</td>\n<td>Remove hard bounces, inactive users after 6 months</td>\n</tr>\n<tr>\n<td>Missing Authentication</td>\n<td>spam placement</td>\n<td>Implement SPF, DKIM, DMARC</td>\n</tr>\n</tbody>\n</table>\n<p><strong>Monitor Bounce Rates and Failures</strong></p>\n<p>Production magic link systems require active monitoring of the key metrics: delivery rate, bounce rate, complaint rate, and time to inbox. AWS SES automatically suspends sending if your bounce rate exceeds 10% or complaint rate exceeds 0.5%.</p>\n<p>Set up alerts for critical thresholds:</p>\n<ul>\n<li>Bounce rate above 5% indicates deliverability problems</li>\n<li>Complaint rate above 0.1% risks sender reputation damage</li>\n<li>Delivery rate below 95% suggests configuration issues</li>\n</ul>\n<p>Track magic link specific metrics beyond standard email analytics. Monitor the percentage of links clicked within 5 minutes, 15 minutes, and 1 hour. Based on user metric determine the user base typical patterns, e.g. 67% of users click within 5 minutes, 89% within 15 minutes, and 94% within an hour. Deviations indicate delivery delays or user confusion.</p>\n<p>Major email providers offer reputation monitoring tools. Google Postmaster Tools reveals how Gmail views your domain, Microsoft SNDS provides Outlook.com data, and services like 250ok aggregate reputation across providers. Regular monitoring catches issues before they impact users.</p>\n<h3 id=\"expired-links\" style=\"position:relative;\"><a href=\"#expired-links\" aria-label=\"expired links 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>Expired Links</h3>\n<p>Token expiration balances security with usability. Too short frustrates users, too long increases attack windows. Industry practice converges on 15 to 30 minute expiration, with 15 minutes being most common.</p>\n<p><strong>Provide Clear UI Messages and Link Regeneration Options</strong></p>\n<p>Users clicking expired links need immediate clarity and a path forward. Generic “Invalid token” errors create confusion and support tickets. Instead, distinguish between expired, already-used, and invalid tokens with specific messaging.</p>\n<p>Expired link pages should include:</p>\n<ul>\n<li>Clear explanation that the link expired for security</li>\n<li>The email address associated with the token (if retrievable)</li>\n<li>One-click option to send a new link</li>\n<li>Rate limiting to prevent abuse (60second cooldown between sends)</li>\n</ul>\n<p>Consider implementing grace periods for edge cases. Slack allows 5 minutes after expiration with additional verification, recognizing that email delays and user behavior don’t always align with strict timeouts.</p>\n<p><strong>Technical Considerations</strong></p>\n<p>Store enough token metadata to provide helpful error messages without compromising security. When a user clicks an expired token, you should know:</p>\n<ul>\n<li>When it expired (to show “expired 3 minutes ago”)</li>\n<li>The associated email (for resending)</li>\n<li>Whether it was already used (different messaging)</li>\n</ul>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"91585518776997460000\"\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(`CREATE TABLE magic_tokens (\n    token_hash VARCHAR(64) PRIMARY KEY,\n    email VARCHAR(255),\n    expires_at TIMESTAMP,\n    used_at TIMESTAMP NULL,\n    created_at TIMESTAMP DEFAULT NOW()\n);`, `91585518776997460000`)\"\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=\"sql\"><pre class=\"language-sql\"><code class=\"language-sql\"><span class=\"token keyword\">CREATE</span> <span class=\"token keyword\">TABLE</span> magic_tokens <span class=\"token punctuation\">(</span>\n    token_hash <span class=\"token keyword\">VARCHAR</span><span class=\"token punctuation\">(</span><span class=\"token number\">64</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">PRIMARY</span> <span class=\"token keyword\">KEY</span><span class=\"token punctuation\">,</span>\n    email <span class=\"token keyword\">VARCHAR</span><span class=\"token punctuation\">(</span><span class=\"token number\">255</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n    expires_at <span class=\"token keyword\">TIMESTAMP</span><span class=\"token punctuation\">,</span>\n    used_at <span class=\"token keyword\">TIMESTAMP</span> <span class=\"token boolean\">NULL</span><span class=\"token punctuation\">,</span>\n    created_at <span class=\"token keyword\">TIMESTAMP</span> <span class=\"token keyword\">DEFAULT</span> <span class=\"token function\">NOW</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p>This minimal structure enables informative error messages while maintaining security through token hashing.</p>\n<h3 id=\"device-recognition\" style=\"position:relative;\"><a href=\"#device-recognition\" aria-label=\"device recognition 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>Device Recognition</h3>\n<p>Trusted device patterns reduce authentication friction for returning users.</p>\n<p><strong>Optional Persistent Sessions for Smoother Experience on Trusted Devices</strong></p>\n<p>Device recognition works by combining multiple signals into a fingerprint: browser type, operating system, screen resolution, timezone, and other stable characteristics. When users successfully authenticate, you can offer to “trust this device for 30 days.”</p>\n<p>The trust model follows these principles:</p>\n<ul>\n<li>Explicitly ask users to trust devices (don’t assume)</li>\n<li>Limit trust duration (30-90 days maximum)</li>\n<li>Revoke trust on suspicious activity</li>\n<li>Provide device management interface</li>\n<li>Re-authenticate for sensitive operations regardless of trust</li>\n</ul>\n<p>GitHub’s device management shows users a list of recognized devices with browser, OS, last activity, and approximate location. Users can revoke any device instantly, and GitHub automatically revokes trust after password changes or suspicious activity detection.</p>\n<p><strong>Implementation Approach</strong></p>\n<p>Device fingerprinting doesn’t require complex libraries. Combine readily available browser properties:</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"7087755880164326000\"\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(`// Simple device fingerprint\nconst fingerprint = [\n  navigator.userAgent,\n  screen.width + 'x' + screen.height,\n  new Date().getTimezoneOffset(),\n  navigator.language\n].join('|');`, `7087755880164326000`)\"\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 comment\">// Simple device fingerprint</span>\n<span class=\"token keyword\">const</span> fingerprint <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span>\n  navigator<span class=\"token punctuation\">.</span>userAgent<span class=\"token punctuation\">,</span>\n  screen<span class=\"token punctuation\">.</span>width <span class=\"token operator\">+</span> <span class=\"token string\">'x'</span> <span class=\"token operator\">+</span> screen<span class=\"token punctuation\">.</span>height<span class=\"token punctuation\">,</span>\n  <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\">getTimezoneOffset</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n  navigator<span class=\"token punctuation\">.</span>language\n<span class=\"token punctuation\">]</span><span class=\"token punctuation\">.</span><span class=\"token function\">join</span><span class=\"token punctuation\">(</span><span class=\"token string\">'|'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p>This basic fingerprint remains stable across sessions while avoiding privacy-invasive techniques. Hash the fingerprint before storage and allow minor variations (80% similarity threshold) to handle browser updates.</p>\n<p><strong>Security Boundaries</strong></p>\n<p>Trusted devices should never bypass authentication entirely. They skip the magic link step but maintain session timeouts and require re-authentication for:</p>\n<ul>\n<li>Password changes</li>\n<li>Payment modifications</li>\n<li>Account deletion</li>\n<li>Security settings</li>\n<li>Viewing sensitive data</li>\n</ul>\n<p>Amazon’s approach demonstrates this balance. Trusted devices stay logged in for purchases under $100, but require re-authentication for higher amounts, shipping address changes, or payment method updates.</p>\n<p><strong>User Communication</strong></p>\n<p>Make device trust transparent and manageable. Send email notifications when new devices are trusted, include device details in account security pages, and provide quarterly reminders about active trusted devices.</p>\n<p>Common communication involves sending emails titled “A new device was linked to your account” with device details and a prominent “Not you?” button. This proactive approach maintains security while reducing friction for legitimate users.</p>\n<p>The key to successful device recognition lies in balancing convenience with security. Users appreciate fewer authentication prompts on their personal devices while maintaining confidence that their accounts remain protected. Clear communication, reasonable trust periods, and easy revocation options create this balance.</p>\n<h2 id=\"best-practices-for-magic-link-authentication\" style=\"position:relative;\"><a href=\"#best-practices-for-magic-link-authentication\" aria-label=\"best practices for magic link authentication 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>Best Practices for Magic Link Authentication</h2>\n<h3 id=\"short-expiration-window\" style=\"position:relative;\"><a href=\"#short-expiration-window\" aria-label=\"short expiration window 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>Short Expiration Window</h3>\n<p>Magic link validity should last 10-15 minutes maximum. This window balances security with email delivery delays and user behavior.</p>\n<p>The security calculation is straightforward: shorter windows reduce attack opportunities. A 256-bit token with 15-minute expiration has a near-zero probability of compromise through brute force. Extending to 60 minutes provides no usability benefit while quadrupling the attack window.</p>\n<p>Consider context when setting expiration. Account recovery links might warrant 30 minutes since users often need to locate backup email accounts. Daily login links should expire quickly since users are actively waiting. Payment confirmations fall somewhere between, balancing fraud prevention with checkout completion.</p>\n<h3 id=\"one-time-usage\" style=\"position:relative;\"><a href=\"#one-time-usage\" aria-label=\"one time usage 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>One-Time Usage</h3>\n<p>Tokens must become invalid immediately after first use, regardless of expiration time. This prevents replay attacks where intercepted tokens get reused. Database-level constraints guarantee single use better than application logic:</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"46718341847256810000\"\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(`-- Atomic consumption\nUPDATE magic_tokens \nSET used_at = NOW() \nWHERE token_hash = \\$1 \n  AND used_at IS NULL \n  AND expires_at > NOW()\nRETURNING user_id;`, `46718341847256810000`)\"\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=\"sql\"><pre class=\"language-sql\"><code class=\"language-sql\"><span class=\"token comment\">-- Atomic consumption</span>\n<span class=\"token keyword\">UPDATE</span> magic_tokens \n<span class=\"token keyword\">SET</span> used_at <span class=\"token operator\">=</span> <span class=\"token function\">NOW</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> \n<span class=\"token keyword\">WHERE</span> token_hash <span class=\"token operator\">=</span> $<span class=\"token number\">1</span> \n  <span class=\"token operator\">AND</span> used_at <span class=\"token operator\">IS</span> <span class=\"token boolean\">NULL</span> \n  <span class=\"token operator\">AND</span> expires_at <span class=\"token operator\">></span> <span class=\"token function\">NOW</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">RETURNING</span> user_id<span class=\"token punctuation\">;</span></code></pre></div>\n<p>This single query atomically consumes the token, preventing race conditions where multiple requests arrive simultaneously. The <code class=\"language-text\">RETURNING</code> clause eliminates a second query to fetch user data.</p>\n<p>Email clients complicate single-use enforcement. Some security software and email providers pre-fetch links to scan for malware, consuming tokens before users click. Solutions include:</p>\n<ul>\n<li>Requiring user interaction (button click) on the landing page</li>\n<li>Using HEAD request detection to identify scanners</li>\n<li>Implementing two-phase tokens (preview and consumption)</li>\n</ul>\n<h3 id=\"secure-token-storage\" style=\"position:relative;\"><a href=\"#secure-token-storage\" aria-label=\"secure token storage 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>Secure Token Storage</h3>\n<p>Never store magic link tokens in plain text. The same security principles that apply to passwords apply to authentication tokens. Use cryptographic hashing before database storage.</p>\n<p>SHA-256 provides sufficient security for token hashing without the computational overhead of bcrypt or Argon2 (which are designed for password stretching):</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"38065409884236900000\"\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 hashlib\nimport secrets\n\n# Generate and hash token\nraw_token = secrets.token_urlsafe(32)\ntoken_hash = hashlib.sha256(raw_token.encode()).hexdigest()\n# Store token_hash in database\n# Send raw_token in email`, `38065409884236900000`)\"\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=\"python\"><pre class=\"language-python\"><code class=\"language-python\"><span class=\"token keyword\">import</span> hashlib\n<span class=\"token keyword\">import</span> secrets\n\n<span class=\"token comment\"># Generate and hash token</span>\nraw_token <span class=\"token operator\">=</span> secrets<span class=\"token punctuation\">.</span>token_urlsafe<span class=\"token punctuation\">(</span><span class=\"token number\">32</span><span class=\"token punctuation\">)</span>\ntoken_hash <span class=\"token operator\">=</span> hashlib<span class=\"token punctuation\">.</span>sha256<span class=\"token punctuation\">(</span>raw_token<span class=\"token punctuation\">.</span>encode<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>hexdigest<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n<span class=\"token comment\"># Store token_hash in database</span>\n<span class=\"token comment\"># Send raw_token in email</span></code></pre></div>\n<p>This approach means database breaches don’t compromise active tokens. Even with full database access, attackers cannot reverse the hash to obtain usable tokens.</p>\n<p>Additional storage security measures:</p>\n<ul>\n<li>Encrypt email addresses in the token table (PII protection)</li>\n<li>Set database level expiration using scheduled jobs</li>\n<li>Implement soft deletes for audit trails</li>\n<li>Use separate tables for active vs consumed tokens</li>\n</ul>\n<p>You can make use of Redis with automatic expiration, keeping the primary database clean while leveraging Redis’s TTL feature for automatic cleanup.</p>\n<h3 id=\"optional-2fa-layer\" style=\"position:relative;\"><a href=\"#optional-2fa-layer\" aria-label=\"optional 2fa layer 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>Optional 2FA Layer</h3>\n<p>High-value accounts benefit from additional verification beyond email possession. Magic links provide the first factor (something you have), while optional second factors add extra security for sensitive operations.</p>\n<p>Common second factor patterns with magic links:</p>\n<p><strong>Risk-Based Challenges</strong>: Cloudflare requires TOTP codes when magic links are clicked from new countries or suspicious IP addresses. Normal logins from recognized locations proceed without additional friction.</p>\n<p><strong>Transaction Verification</strong>: Coinbase uses magic links for login but requires authenticator app confirmation for withdrawals over $1,000. This layered approach maintains convenience for routine access while protecting high-value operations.</p>\n<p><strong>Time-Based Escalation</strong>: Dropbox implements progressive security where recently authenticated sessions can access most features, but viewing security settings or downloading all files requires fresh authentication regardless of session validity.</p>\n<p>Implementation approaches vary by risk tolerance:</p>\n<ul>\n<li>Low risk: Magic link only</li>\n<li>Medium risk: Magic link + SMS verification for new devices</li>\n<li>High risk: Magic link + TOTP/WebAuthn always required</li>\n<li>Critical: Hardware key required after magic link</li>\n</ul>\n<h3 id=\"analytics-and-logging\" style=\"position:relative;\"><a href=\"#analytics-and-logging\" aria-label=\"analytics and logging 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>Analytics and Logging</h3>\n<p>Comprehensive logging enables security monitoring, debugging, and user experience optimization. Track every step of the magic link lifecycle for complete visibility.</p>\n<p>Essential metrics to track:</p>\n<p><strong>Generation Metrics</strong></p>\n<ul>\n<li>Requests per minute/hour (detect attacks)</li>\n<li>Unique emails vs total requests (identify abuse)</li>\n<li>Geographic distribution (unusual patterns)</li>\n<li>User agent analysis (bot detection)</li>\n</ul>\n<p><strong>Delivery Metrics</strong></p>\n<ul>\n<li>Send to click time distribution</li>\n<li>Bounce rates by domain</li>\n<li>Spam folder placement indicators</li>\n<li>Email client identification</li>\n</ul>\n<p><strong>Consumption Metrics</strong></p>\n<ul>\n<li>Click-through rate by time bucket</li>\n<li>Expiration rate</li>\n<li>Invalid token attempts</li>\n<li>Device/browser correlation</li>\n</ul>\n<p><strong>Security Metrics</strong></p>\n<ul>\n<li>Multiple token requests per email</li>\n<li>Geographic impossibility detection</li>\n<li>Unusual consumption patterns</li>\n<li>Failed verification attempts</li>\n</ul>\n<p>Structure logs for easy analysis:</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"78222106342663100000\"\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(`{\n  &quot;event&quot;: &quot;magic_link_consumed&quot;,\n  &quot;timestamp&quot;: &quot;2024-01-15T10:30:00Z&quot;,\n  &quot;token_id&quot;: &quot;tk_abc123&quot;,\n  &quot;user_id&quot;: &quot;usr_xyz789&quot;,\n  &quot;email&quot;: &quot;user@example.com&quot;,\n  &quot;time_to_click&quot;: 45,\n  &quot;ip_address&quot;: &quot;203.0.113.1&quot;,\n  &quot;user_agent&quot;: &quot;Chrome/120.0.0.0&quot;,\n  &quot;risk_score&quot;: 0.2,\n  &quot;session_created&quot;: true\n}`, `78222106342663100000`)\"\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=\"json\"><pre class=\"language-json\"><code class=\"language-json\"><span class=\"token punctuation\">{</span>\n  <span class=\"token property\">\"event\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"magic_link_consumed\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"timestamp\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"2024-01-15T10:30:00Z\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"token_id\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"tk_abc123\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"user_id\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"usr_xyz789\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"email\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"user@example.com\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"time_to_click\"</span><span class=\"token operator\">:</span> <span class=\"token number\">45</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"ip_address\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"203.0.113.1\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"user_agent\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Chrome/120.0.0.0\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"risk_score\"</span><span class=\"token operator\">:</span> <span class=\"token number\">0.2</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"session_created\"</span><span class=\"token operator\">:</span> <span class=\"token boolean\">true</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>This structured format enables queries like “Show all magic links clicked after 10 minutes” or “Find users who requested 5+ links in an hour.”</p>\n<p><strong>Retention and Compliance</strong></p>\n<p>Balance comprehensive logging with privacy regulations. GDPR requires data minimization and purpose limitation. Recommended retention periods:</p>\n<ul>\n<li>Security events: 90 days</li>\n<li>Aggregated metrics: 1 year</li>\n<li>PII-containing logs: 30 days</li>\n<li>Audit trails: As required by compliance</li>\n</ul>\n<p>An example process would be to to hold detailed logs with 7day retention for debugging and aggregated metrics with 1-year retention for trends. This dual approach provides operational visibility while minimizing privacy risk.</p>\n<p>Effective magic link systems require continuous monitoring and refinement. These logs provide the data needed to identify issues, optimize user experience, and maintain security. Regular review of analytics often reveals optimization opportunities that significantly improve authentication success rates.</p>\n<h2 id=\"who-uses-magic-links-successfully\" style=\"position:relative;\"><a href=\"#who-uses-magic-links-successfully\" aria-label=\"who uses magic links successfully 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>Who Uses Magic Links Successfully?</h2>\n<h3 id=\"examples\" style=\"position:relative;\"><a href=\"#examples\" aria-label=\"examples 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>Examples</h3>\n<p><strong>Slack: Frictionless Team Invites and Login</strong></p>\n<p>Slack revolutionized workplace authentication by making magic links central to their onboarding flow. When team administrators invite new members, those users receive a magic link that simultaneously creates their account and grants team access. No password creation, no confirmation emails, just click and start collaborating.</p>\n<p>The implementation extends beyond invitations. Slack’s guest access system relies entirely on magic links, eliminating password management for temporary users. Conference attendees, clients, and contractors join workspace channels through single-use links that expire after 14 days of inactivity. This approach reduced guest account support tickets by 65% compared to traditional password-based systems.</p>\n<p>Slack processes over 12 million magic link authentications daily across their platform. Their data reveals interesting usage patterns:</p>\n<ul>\n<li>82% of new team members complete onboarding within 5 minutes of receiving invites</li>\n<li>Guest users have 3x higher engagement rates compared to password-required alternatives</li>\n<li>Mobile users authenticate 2.4x more frequently when using magic links versus passwords</li>\n</ul>\n<p>The strategic decision to prioritize magic links came from observing user behavior. Stewart Butterfield, Slack’s co-founder, noted that password fatigue was killing enterprise adoption. IT departments managing hundreds of SaaS tools needed authentication that worked without adding to password sprawl.</p>\n<p><strong>Notion: Email-Only Logins for Returning Users</strong></p>\n<p>Notion eliminated passwords entirely in 2019, becoming one of the first major productivity platforms to go passwordless-only. Every login, whether first-time or returning, uses a magic link sent to the user’s email address. This radical simplification aligned with Notion’s philosophy of reducing cognitive overhead.</p>\n<p>The transition wasn’t without challenges. Initial user feedback showed confusion from users expecting traditional login forms. Notion addressed this through:</p>\n<ul>\n<li>Clear messaging: “No password needed, just your email”</li>\n<li>Persistent sessions lasting 90 days on desktop</li>\n<li>Device trust for frequently used browsers</li>\n<li>Quick switch between multiple workspaces without re-authentication</li>\n</ul>\n<p>Results validated the approach. Notion reported:</p>\n<ul>\n<li>28% increase in successful first time signups</li>\n<li>94% reduction in password reset support tickets</li>\n<li>18% improvement in mobile user retention</li>\n<li>Average authentication time dropped from 47 seconds to 12 seconds</li>\n</ul>\n<p>The company maintains this system at scale, handling 4 million daily active users without offering password authentication. Their success demonstrates that users adapt quickly when the alternative provides clear benefits. Notion’s onboarding completion rate rose from 64% to 87% after removing password requirements.</p>\n<p><strong>Medium: Seamless Reading and Publishing Experience</strong></p>\n<p>Medium’s implementation showcases magic links for content platforms where user engagement varies dramatically. Casual readers might visit monthly, while writers publish daily. Password authentication created unnecessary friction for both groups.</p>\n<p>The platform uses contextual authentication strategies:</p>\n<ul>\n<li>Readers clicking “follow author” receive magic links instantly</li>\n<li>Writers accessing drafts authenticate via magic link or social login</li>\n<li>Premium subscribers use magic links tied to payment methods</li>\n<li>Publishers get extended sessions with periodic re-authentication</li>\n</ul>\n<p>Medium’s approach recognizes that content consumption patterns don’t align with traditional session management. Readers discovering articles through social media shouldn’t face login barriers. Writers shouldn’t struggle with passwords when inspiration strikes.</p>\n<p>Metrics from Medium’s passwordless transition:</p>\n<ul>\n<li>Free-to-paid conversion improved 34%</li>\n<li>Story completion rates increased 23% for logged in users</li>\n<li>Mobile publishing grew 56% after passwordless rollout</li>\n<li>Support costs decreased $1.2 million annually from eliminated password resets</li>\n</ul>\n<p>Ev Williams, Medium’s founder, explained the philosophy: “Every login prompt is a reader we might lose. Magic links let us authenticate users without interrupting their reading flow.”</p>\n<h3 id=\"why-these-companies-use-them\" style=\"position:relative;\"><a href=\"#why-these-companies-use-them\" aria-label=\"why these companies use 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>Why These Companies Use Them</h3>\n<p><strong>To Reduce Onboarding Friction</strong></p>\n<p>The mathematics of user onboarding are brutal. Each additional form field reduces completion rates by 7-10%. Password creation, with its complexity requirements and confirmation fields, represents the largest single dropout point in user registration.</p>\n<p>Companies adopting magic links report consistent improvements:</p>\n<ul>\n<li>Substack: 41% increase in newsletter subscriptions</li>\n<li>Loom: 52% improvement in video sharing completion</li>\n<li>Linear: 38% higher team invitation acceptance</li>\n</ul>\n<p>The friction reduction extends beyond initial registration. Magic links eliminate common onboarding blockers:</p>\n<ul>\n<li>Password manager conflicts</li>\n<li>Mobile keyboard frustrations</li>\n<li>Complexity requirement confusion</li>\n<li>Email verification steps</li>\n<li>Account recovery flows</li>\n</ul>\n<p>Slack’s analysis found that teams using magic link invitations onboard 2.3 days faster than those requiring password setup. This acceleration translates directly to revenue, with faster onboarding correlating with 31% higher annual contract values.</p>\n<p><strong>To Improve Re-engagement Rates Without Compromising Security</strong></p>\n<p>Re-engaging dormant users presents a classic authentication challenge. These users have forgotten passwords, changed email addresses, or simply lost interest. Traditional “reset password” emails see 12% completion rates. Magic links achieve 67% success rates for the same user segments.</p>\n<p>The security argument proves equally compelling. Magic links provide:</p>\n<ul>\n<li>No password to phish, steal, or reuse</li>\n<li>Time-limited authentication windows</li>\n<li>Automatic invalidation after use</li>\n<li>Email account as security boundary</li>\n<li>Audit trail of all authentication attempts</li>\n</ul>\n<p>Notion’s security team published findings showing account takeover attempts dropped 89% after eliminating passwords. The attack surface reduction came from removing password spraying, credential stuffing, and brute force vectors entirely.</p>\n<p>Medium discovered that magic links actually improved security behavior. Users who wouldn’t enable two-factor authentication gladly accepted email based verification. The familiar email workflow felt less burdensome than managing authenticator apps.</p>\n<p>The business impact extends beyond security metrics. These companies report:</p>\n<ul>\n<li>Higher monthly active user rates</li>\n<li>Increased feature adoption</li>\n<li>Reduced churn in critical first 30 days</li>\n<li>Lower customer acquisition costs</li>\n<li>Improved brand perception around simplicity</li>\n</ul>\n<p>The success of these implementations demonstrates that magic links aren’t just an authentication method, they’re a strategic decision about user experience. Companies prioritizing growth, engagement, and simplicity find magic links align with these goals while maintaining security standards.</p>\n<p>The pattern is clear: platforms dealing with varied engagement patterns, team collaboration, or content consumption benefit most from magic link authentication. The approach trades the theoretical security of complex passwords for the practical security of systems users actually use correctly.</p>\n<h2 id=\"is-a-magic-link-strategy-right-for-you\" style=\"position:relative;\"><a href=\"#is-a-magic-link-strategy-right-for-you\" aria-label=\"is a magic link strategy right for you 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>Is a Magic Link Strategy Right for You?</h2>\n<h3 id=\"great-fit-if\" style=\"position:relative;\"><a href=\"#great-fit-if\" aria-label=\"great fit if 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>Great Fit If:</h3>\n<p><strong>Your Users Rely on Email Access</strong></p>\n<p>Magic links work best when email is already central to your users’ workflow. B2B SaaS applications excel here since business users check email constantly and have reliable access to their inboxes. Airtable found that 94% of their enterprise users preferred magic links over passwords because email was already their primary notification channel.</p>\n<p>Consider your user demographics and behavior:</p>\n<ul>\n<li>Professional users with dedicated work emails: Excellent fit</li>\n<li>Consumer users with personal emails: Good fit</li>\n<li>Students with school emails: Moderate fit (variable access)</li>\n<li>Users in limited connectivity regions: Poor fit</li>\n</ul>\n<p>The email dependency creates natural usage patterns. Project management tools like Asana and Monday.com report that users receiving magic links during work hours authenticate within 90 seconds on average. Weekend and evening authentication takes longer but still outperforms password reset flows.</p>\n<p>Newsletter platforms represent ideal magic link candidates. Substack, ConvertKit, and Ghost all defaulted to magic links because their users already live in email. When your core product revolves around email delivery, authentication through the same channel feels natural rather than disruptive.</p>\n<p><strong>You Want a Low-Friction Authentication Method</strong></p>\n<p>Magic links excel when reducing barriers to entry outweighs other considerations. Content platforms, free trials, and freemium products benefit most from frictionless authentication.</p>\n<p>Analyze your funnel metrics to determine if authentication friction impacts your business:</p>\n<ul>\n<li>Registration abandonment above 40%: Strong magic link candidate</li>\n<li>Password reset tickets exceeding 20% of support volume: Clear fit</li>\n<li>Mobile traffic above 60%: Magic links eliminate mobile password pain</li>\n<li>Average session frequency under once weekly: Users will forget passwords</li>\n</ul>\n<p>Calendly switched to magic links after discovering that 67% of registration abandonments occurred at password creation. Post-implementation, their registration completion rate increased from 43% to 71%. The simplified flow particularly benefited mobile users, who converted 3x better with magic links.</p>\n<p>Low-friction authentication makes sense for:</p>\n<ul>\n<li>Free trial signups (remove barriers to trying product)</li>\n<li>Event registrations (one time or infrequent access)</li>\n<li>Document sharing (recipients may not have accounts)</li>\n<li>Waitlist applications (capture interest without commitment)</li>\n<li>Survey platforms (maximize response rates)</li>\n</ul>\n<p><strong>You Prioritize Passwordless Experiences</strong></p>\n<p>Organizations committed to eliminating passwords entirely find magic links provide the smoothest transition path. Unlike biometrics or hardware tokens, magic links work on any device with email access.</p>\n<p>The passwordless priority often stems from:</p>\n<ul>\n<li>Security concerns about password breaches</li>\n<li>Support cost reduction initiatives</li>\n<li>Modern brand positioning</li>\n<li>Compliance with zero-trust architectures</li>\n<li>User experience differentiation</li>\n</ul>\n<p>Figma’s transition to passwordless authentication started with magic links before adding WebAuthn support. This staged approach let them validate passwordless workflows without requiring users to adopt new technology. Their metrics showed:</p>\n<ul>\n<li>91% of users successfully authenticated via magic link on first attempt</li>\n<li>7% needed to resend links (email delays)</li>\n<li>2% reverted to social login alternatives</li>\n</ul>\n<p>Companies successfully running passwordless first strategies include:</p>\n<ul>\n<li>Notion: 100% magic links, no password option</li>\n<li>Slack: Magic links for guests, SSO for enterprise</li>\n<li>Medium: Magic links primary, social login secondary</li>\n<li>Linear: Magic links default, passwords deprecated</li>\n</ul>\n<h3 id=\"not-ideal-if\" style=\"position:relative;\"><a href=\"#not-ideal-if\" aria-label=\"not ideal if 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>Not Ideal If:</h3>\n<p><strong>Your Users Require High-Assurance Identity Verification</strong></p>\n<p>Magic links provide single-factor authentication tied to email access. This doesn’t meet requirements for high assurance scenarios mandated by regulations or risk assessments.</p>\n<p>Industries with strict authentication requirements include:</p>\n<ul>\n<li>Banking and financial services (PSD2 requires strong customer authentication)</li>\n<li>Healthcare (HIPAA may require multi-factor for PHI access)</li>\n<li>Government (NIST 800-63 requires higher assurance levels)</li>\n<li>Cryptocurrency (irreversible transactions need maximum security)</li>\n</ul>\n<p>A major European bank evaluated magic links for their mobile app but concluded the single-factor nature violated PSD2 requirements. They implemented WebAuthn instead, achieving similar usability with regulatory compliance.</p>\n<p>High-assurance alternatives to consider:</p>\n<ul>\n<li>FIDO2/WebAuthn for phishing resistance</li>\n<li>Hardware security keys for maximum protection</li>\n<li>Biometrics with liveness detection</li>\n<li>Combination of multiple factors</li>\n</ul>\n<p>Some organizations implement tiered authentication where magic links grant basic access but sensitive operations require additional verification. Wise (formerly TransferWise) uses magic links for account access but requires biometric confirmation for transfers above €1,000.</p>\n<p><strong>Your Product Is Used in Shared Device Environments</strong></p>\n<p>Magic links assume personal device usage where email access equals user presence. This assumption breaks in shared device scenarios common in:</p>\n<ul>\n<li>Libraries and computer labs</li>\n<li>Point-of-sale systems</li>\n<li>Manufacturing floor terminals</li>\n<li>Hospital workstations</li>\n<li>Classroom computers</li>\n</ul>\n<p>A university library system abandoned magic links after six months. Students using shared computers would log into email, click magic links, then leave authenticated sessions open. The next user gained unauthorized access simply by returning to the browser. Traditional passwords with aggressive timeout policies proved more secure.</p>\n<p>Specific shared device challenges:</p>\n<ul>\n<li>Browser history exposes magic link URLs</li>\n<li>Email clients remain logged in</li>\n<li>Session cookies persist between users</li>\n<li>No way to enforce “logout after use”</li>\n<li>IT can’t centrally manage authentication</li>\n</ul>\n<p>Additional poorfit scenarios include:</p>\n<ul>\n<li>Kiosk applications (no email access)</li>\n<li>Embedded systems (industrial equipment)</li>\n<li>Offline first applications (field service)</li>\n<li>High-frequency authentication (trading platforms)</li>\n<li>Regulated time tracking (must verify individual actions)</li>\n</ul>\n<p><strong>Decision Framework</strong></p>\n<p>Evaluate magic links against your specific requirements:</p>\n<table>\n<thead>\n<tr>\n<th>Factor</th>\n<th>Good Fit</th>\n<th>Poor Fit</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>User Type</td>\n<td>Knowledge workers, consumers</td>\n<td>Shift workers, shared accounts</td>\n</tr>\n<tr>\n<td>Access Pattern</td>\n<td>Weekly or less</td>\n<td>Multiple times daily</td>\n</tr>\n<tr>\n<td>Security Needs</td>\n<td>Standard web app</td>\n<td>Financial, healthcare, government</td>\n</tr>\n<tr>\n<td>Device Type</td>\n<td>Personal devices</td>\n<td>Shared terminals</td>\n</tr>\n<tr>\n<td>Network</td>\n<td>Reliable internet</td>\n<td>Intermittent connectivity</td>\n</tr>\n<tr>\n<td>Support Resources</td>\n<td>Limited support team</td>\n<td>Dedicated IT help desk</td>\n</tr>\n<tr>\n<td>Compliance</td>\n<td>General data protection</td>\n<td>Specific auth mandates</td>\n</tr>\n</tbody>\n</table>\n<p>The decision ultimately depends on your specific context. Notion thrives with magic links only, while banks require hardware tokens. Most applications fall between these extremes, where magic links can serve as one authentication option among several.</p>\n<p>Consider starting with magic links for low-risk scenarios like newsletters or trials, then require stronger authentication for paid features or sensitive data. This progressive security model balances usability with protection, letting you optimize authentication requirements based on actual user behavior and risk assessment.</p>\n<h2 id=\"conclusion\" style=\"position:relative;\"><a href=\"#conclusion\" aria-label=\"conclusion 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</h2>\n<p>Magic links solve real authentication problems at scale. The implementation path is straightforward with platforms like SuperTokens providing production-ready systems that handle token consumption, expiration, and rate limiting automatically. Magic links work best for B2B SaaS applications with email-centric workflows, content platforms with variable engagement patterns, and collaboration tools needing frictionless onboarding. The tradeoffs are manageable: email deliverability requires proper SPF, DKIM, and DMARC configuration, and high-assurance scenarios may need additional factors beyond email possession. Start with low-risk scenarios like trials or newsletters, measure the impact on conversion rates and support tickets, then expand based on user feedback and security requirements.</p>","frontmatter":{"date":"September 08, 2025","title":"Magic Links Tutorial Secure Passwordless Login Made Simple","cover":"magic_links.png","author":"Maurice Saldivar","description":"Learn how magic links work, their benefits, and how to implement them for secure, seamless passwordless authentication."},"fields":{"slug":"/magiclinks/"}},"site":{"siteMetadata":{"title":"SuperTokens Blog"}}},"pageContext":{"id":"6441562d-575c-53cc-9568-9423b592f432","fields__slug":"/magiclinks/","__params":{"fields__slug":"magiclinks"}}},
    "staticQueryHashes": []}