{
  "schemaVersion": "1.0",
  "item": {
    "slug": "twofactor",
    "name": "Two Factor Authentication Best Practices",
    "source": "tencent",
    "type": "skill",
    "category": "安全合规",
    "sourceUrl": "https://clawhub.ai/StevenFengLi/twofactor",
    "canonicalUrl": "https://clawhub.ai/StevenFengLi/twofactor",
    "targetPlatform": "OpenClaw"
  },
  "install": {
    "downloadMode": "redirect",
    "downloadUrl": "/downloads/twofactor",
    "sourceDownloadUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=twofactor",
    "sourcePlatform": "tencent",
    "targetPlatform": "OpenClaw",
    "installMethod": "Manual import",
    "extraction": "Extract archive",
    "prerequisites": [
      "OpenClaw"
    ],
    "packageFormat": "ZIP package",
    "includedAssets": [
      "SKILL.md"
    ],
    "primaryDoc": "SKILL.md",
    "quickSetup": [
      "Download the package from Yavira.",
      "Extract the archive and review SKILL.md first.",
      "Import or place the package into your OpenClaw setup."
    ],
    "agentAssist": {
      "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
      "steps": [
        "Download the package from Yavira.",
        "Extract it into a folder your agent can access.",
        "Paste one of the prompts below and point your agent at the extracted folder."
      ],
      "prompts": [
        {
          "label": "New install",
          "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
        },
        {
          "label": "Upgrade existing",
          "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
        }
      ]
    },
    "sourceHealth": {
      "source": "tencent",
      "slug": "twofactor",
      "status": "healthy",
      "reason": "direct_download_ok",
      "recommendedAction": "download",
      "checkedAt": "2026-04-29T17:12:45.136Z",
      "expiresAt": "2026-05-06T17:12:45.136Z",
      "httpStatus": 200,
      "finalUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=twofactor",
      "contentType": "application/zip",
      "probeMethod": "head",
      "details": {
        "probeUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=twofactor",
        "contentDisposition": "attachment; filename=\"twofactor-0.1.0.zip\"",
        "redirectLocation": null,
        "bodySnippet": null,
        "slug": "twofactor"
      },
      "scope": "item",
      "summary": "Item download looks usable.",
      "detail": "Yavira can redirect you to the upstream package for this item.",
      "primaryActionLabel": "Download for OpenClaw",
      "primaryActionHref": "/downloads/twofactor"
    },
    "validation": {
      "installChecklist": [
        "Use the Yavira download entry.",
        "Review SKILL.md after the package is downloaded.",
        "Confirm the extracted package contains the expected setup assets."
      ],
      "postInstallChecks": [
        "Confirm the extracted package includes the expected docs or setup files.",
        "Validate the skill or prompts are available in your target agent workspace.",
        "Capture any manual follow-up steps the agent could not complete."
      ]
    },
    "downloadPageUrl": "https://openagent3.xyz/downloads/twofactor",
    "agentPageUrl": "https://openagent3.xyz/skills/twofactor/agent",
    "manifestUrl": "https://openagent3.xyz/skills/twofactor/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/twofactor/agent.md"
  },
  "agentAssist": {
    "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
    "steps": [
      "Download the package from Yavira.",
      "Extract it into a folder your agent can access.",
      "Paste one of the prompts below and point your agent at the extracted folder."
    ],
    "prompts": [
      {
        "label": "New install",
        "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
      },
      {
        "label": "Upgrade existing",
        "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
      }
    ]
  },
  "documentation": {
    "source": "clawhub",
    "primaryDoc": "SKILL.md",
    "sections": [
      {
        "title": "Setting Up Two-Factor Authentication",
        "body": "When adding 2FA to your application, configure the twoFactor plugin with your app name as the issuer. This name appears in authenticator apps when users scan the QR code.\n\nimport { betterAuth } from \"better-auth\";\nimport { twoFactor } from \"better-auth/plugins\";\n\nexport const auth = betterAuth({\n  appName: \"My App\", // Used as the default issuer for TOTP\n  plugins: [\n    twoFactor({\n      issuer: \"My App\", // Optional: override the app name for 2FA specifically\n    }),\n  ],\n});\n\nNote: After adding the plugin, run npx @better-auth/cli migrate to add the required database fields and tables."
      },
      {
        "title": "Client-Side Setup",
        "body": "Add the client plugin and configure the redirect behavior for 2FA verification:\n\nimport { createAuthClient } from \"better-auth/client\";\nimport { twoFactorClient } from \"better-auth/client/plugins\";\n\nexport const authClient = createAuthClient({\n  plugins: [\n    twoFactorClient({\n      onTwoFactorRedirect() {\n        window.location.href = \"/2fa\"; // Redirect to your 2FA verification page\n      },\n    }),\n  ],\n});"
      },
      {
        "title": "Enabling 2FA for Users",
        "body": "When a user enables 2FA, require their password for verification. The enable endpoint returns a TOTP URI for QR code generation and backup codes for account recovery.\n\nconst enable2FA = async (password: string) => {\n  const { data, error } = await authClient.twoFactor.enable({\n    password,\n  });\n\n  if (data) {\n    // data.totpURI - Use this to generate a QR code\n    // data.backupCodes - Display these to the user for safekeeping\n  }\n};\n\nImportant: The twoFactorEnabled flag on the user is not set to true until the user successfully verifies their first TOTP code. This ensures users have properly configured their authenticator app before 2FA is fully active."
      },
      {
        "title": "Skipping Initial Verification",
        "body": "If you want to enable 2FA immediately without requiring verification, set skipVerificationOnEnable:\n\ntwoFactor({\n  skipVerificationOnEnable: true, // Not recommended for most use cases\n});\n\nNote: This is generally not recommended as it doesn't confirm the user has successfully set up their authenticator app."
      },
      {
        "title": "TOTP (Authenticator App)",
        "body": "TOTP generates time-based codes using an authenticator app (Google Authenticator, Authy, etc.). Codes are valid for 30 seconds by default."
      },
      {
        "title": "Displaying the QR Code",
        "body": "Use the TOTP URI to generate a QR code for users to scan:\n\nimport QRCode from \"react-qr-code\";\n\nconst TotpSetup = ({ totpURI }: { totpURI: string }) => {\n  return <QRCode value={totpURI} />;\n};"
      },
      {
        "title": "Verifying TOTP Codes",
        "body": "Better Auth accepts codes from one period before and one after the current time, accommodating minor clock differences between devices:\n\nconst verifyTotp = async (code: string) => {\n  const { data, error } = await authClient.twoFactor.verifyTotp({\n    code,\n    trustDevice: true, // Optional: remember this device for 30 days\n  });\n};"
      },
      {
        "title": "TOTP Configuration Options",
        "body": "twoFactor({\n  totpOptions: {\n    digits: 6, // 6 or 8 digits (default: 6)\n    period: 30, // Code validity period in seconds (default: 30)\n  },\n});"
      },
      {
        "title": "OTP (Email/SMS)",
        "body": "OTP sends a one-time code to the user's email or phone. You must implement the sendOTP function to deliver codes."
      },
      {
        "title": "Configuring OTP Delivery",
        "body": "import { betterAuth } from \"better-auth\";\nimport { twoFactor } from \"better-auth/plugins\";\nimport { sendEmail } from \"./email\";\n\nexport const auth = betterAuth({\n  plugins: [\n    twoFactor({\n      otpOptions: {\n        sendOTP: async ({ user, otp }, ctx) => {\n          await sendEmail({\n            to: user.email,\n            subject: \"Your verification code\",\n            text: `Your code is: ${otp}`,\n          });\n        },\n        period: 5, // Code validity in minutes (default: 3)\n        digits: 6, // Number of digits (default: 6)\n        allowedAttempts: 5, // Max verification attempts (default: 5)\n      },\n    }),\n  ],\n});"
      },
      {
        "title": "Sending and Verifying OTP",
        "body": "// Request an OTP to be sent\nconst sendOtp = async () => {\n  const { data, error } = await authClient.twoFactor.sendOtp();\n};\n\n// Verify the OTP code\nconst verifyOtp = async (code: string) => {\n  const { data, error } = await authClient.twoFactor.verifyOtp({\n    code,\n    trustDevice: true,\n  });\n};"
      },
      {
        "title": "OTP Storage Security",
        "body": "Configure how OTP codes are stored in the database:\n\ntwoFactor({\n  otpOptions: {\n    storeOTP: \"encrypted\", // Options: \"plain\", \"encrypted\", \"hashed\"\n  },\n});\n\nFor custom encryption:\n\ntwoFactor({\n  otpOptions: {\n    storeOTP: {\n      encrypt: async (token) => myEncrypt(token),\n      decrypt: async (token) => myDecrypt(token),\n    },\n  },\n});"
      },
      {
        "title": "Backup Codes",
        "body": "Backup codes provide account recovery when users lose access to their authenticator app or phone. They are generated automatically when 2FA is enabled."
      },
      {
        "title": "Displaying Backup Codes",
        "body": "Always show backup codes to users when they enable 2FA:\n\nconst BackupCodes = ({ codes }: { codes: string[] }) => {\n  return (\n    <div>\n      <p>Save these codes in a secure location:</p>\n      <ul>\n        {codes.map((code, i) => (\n          <li key={i}>{code}</li>\n        ))}\n      </ul>\n    </div>\n  );\n};"
      },
      {
        "title": "Regenerating Backup Codes",
        "body": "When users need new codes, regenerate them (this invalidates all previous codes):\n\nconst regenerateBackupCodes = async (password: string) => {\n  const { data, error } = await authClient.twoFactor.generateBackupCodes({\n    password,\n  });\n  // data.backupCodes contains the new codes\n};"
      },
      {
        "title": "Using Backup Codes for Recovery",
        "body": "const verifyBackupCode = async (code: string) => {\n  const { data, error } = await authClient.twoFactor.verifyBackupCode({\n    code,\n    trustDevice: true,\n  });\n};\n\nNote: Each backup code can only be used once and is removed from the database after successful verification."
      },
      {
        "title": "Backup Code Configuration",
        "body": "twoFactor({\n  backupCodeOptions: {\n    amount: 10, // Number of codes to generate (default: 10)\n    length: 10, // Length of each code (default: 10)\n    storeBackupCodes: \"encrypted\", // Options: \"plain\", \"encrypted\"\n  },\n});"
      },
      {
        "title": "Handling 2FA During Sign-In",
        "body": "When a user with 2FA enabled signs in, the response includes twoFactorRedirect: true:\n\nconst signIn = async (email: string, password: string) => {\n  const { data, error } = await authClient.signIn.email(\n    {\n      email,\n      password,\n    },\n    {\n      onSuccess(context) {\n        if (context.data.twoFactorRedirect) {\n          // Redirect to 2FA verification page\n          window.location.href = \"/2fa\";\n        }\n      },\n    }\n  );\n};"
      },
      {
        "title": "Server-Side 2FA Detection",
        "body": "When using auth.api.signInEmail on the server, check for 2FA redirect:\n\nconst response = await auth.api.signInEmail({\n  body: {\n    email: \"user@example.com\",\n    password: \"password\",\n  },\n});\n\nif (\"twoFactorRedirect\" in response) {\n  // Handle 2FA verification\n}"
      },
      {
        "title": "Trusted Devices",
        "body": "Trusted devices allow users to skip 2FA verification on subsequent sign-ins for a configurable period."
      },
      {
        "title": "Enabling Trust on Verification",
        "body": "Pass trustDevice: true when verifying 2FA:\n\nawait authClient.twoFactor.verifyTotp({\n  code: \"123456\",\n  trustDevice: true,\n});"
      },
      {
        "title": "Configuring Trust Duration",
        "body": "twoFactor({\n  trustDeviceMaxAge: 30 * 24 * 60 * 60, // 30 days in seconds (default)\n});\n\nNote: The trust period refreshes on each successful sign-in within the trust window."
      },
      {
        "title": "Session Management",
        "body": "During the 2FA flow:\n\nUser signs in with credentials\nSession cookie is removed (not yet authenticated)\nA temporary two-factor cookie is set (default: 10-minute expiration)\nUser verifies via TOTP, OTP, or backup code\nSession cookie is created upon successful verification\n\nConfigure the two-factor cookie expiration:\n\ntwoFactor({\n  twoFactorCookieMaxAge: 600, // 10 minutes in seconds (default)\n});"
      },
      {
        "title": "Rate Limiting",
        "body": "Better Auth applies built-in rate limiting to all 2FA endpoints (3 requests per 10 seconds). For OTP verification, additional attempt limiting is applied:\n\ntwoFactor({\n  otpOptions: {\n    allowedAttempts: 5, // Max attempts per OTP code (default: 5)\n  },\n});"
      },
      {
        "title": "Encryption at Rest",
        "body": "TOTP secrets are encrypted using symmetric encryption with your auth secret\nBackup codes are stored encrypted by default\nOTP codes can be configured for plain, encrypted, or hashed storage"
      },
      {
        "title": "Constant-Time Comparison",
        "body": "Better Auth uses constant-time comparison for OTP verification to prevent timing attacks."
      },
      {
        "title": "Credential Account Requirement",
        "body": "Two-factor authentication can only be enabled for credential (email/password) accounts. For social accounts, it's assumed the provider already handles 2FA."
      },
      {
        "title": "Disabling 2FA",
        "body": "Allow users to disable 2FA with password confirmation:\n\nconst disable2FA = async (password: string) => {\n  const { data, error } = await authClient.twoFactor.disable({\n    password,\n  });\n};\n\nNote: When 2FA is disabled, trusted device records are revoked."
      },
      {
        "title": "Complete Configuration Example",
        "body": "import { betterAuth } from \"better-auth\";\nimport { twoFactor } from \"better-auth/plugins\";\nimport { sendEmail } from \"./email\";\n\nexport const auth = betterAuth({\n  appName: \"My App\",\n  plugins: [\n    twoFactor({\n      // TOTP settings\n      issuer: \"My App\",\n      totpOptions: {\n        digits: 6,\n        period: 30,\n      },\n      // OTP settings\n      otpOptions: {\n        sendOTP: async ({ user, otp }) => {\n          await sendEmail({\n            to: user.email,\n            subject: \"Your verification code\",\n            text: `Your code is: ${otp}`,\n          });\n        },\n        period: 5,\n        allowedAttempts: 5,\n        storeOTP: \"encrypted\",\n      },\n      // Backup code settings\n      backupCodeOptions: {\n        amount: 10,\n        length: 10,\n        storeBackupCodes: \"encrypted\",\n      },\n      // Session settings\n      twoFactorCookieMaxAge: 600, // 10 minutes\n      trustDeviceMaxAge: 30 * 24 * 60 * 60, // 30 days\n    }),\n  ],\n});"
      }
    ],
    "body": "Setting Up Two-Factor Authentication\n\nWhen adding 2FA to your application, configure the twoFactor plugin with your app name as the issuer. This name appears in authenticator apps when users scan the QR code.\n\nimport { betterAuth } from \"better-auth\";\nimport { twoFactor } from \"better-auth/plugins\";\n\nexport const auth = betterAuth({\n  appName: \"My App\", // Used as the default issuer for TOTP\n  plugins: [\n    twoFactor({\n      issuer: \"My App\", // Optional: override the app name for 2FA specifically\n    }),\n  ],\n});\n\n\nNote: After adding the plugin, run npx @better-auth/cli migrate to add the required database fields and tables.\n\nClient-Side Setup\n\nAdd the client plugin and configure the redirect behavior for 2FA verification:\n\nimport { createAuthClient } from \"better-auth/client\";\nimport { twoFactorClient } from \"better-auth/client/plugins\";\n\nexport const authClient = createAuthClient({\n  plugins: [\n    twoFactorClient({\n      onTwoFactorRedirect() {\n        window.location.href = \"/2fa\"; // Redirect to your 2FA verification page\n      },\n    }),\n  ],\n});\n\nEnabling 2FA for Users\n\nWhen a user enables 2FA, require their password for verification. The enable endpoint returns a TOTP URI for QR code generation and backup codes for account recovery.\n\nconst enable2FA = async (password: string) => {\n  const { data, error } = await authClient.twoFactor.enable({\n    password,\n  });\n\n  if (data) {\n    // data.totpURI - Use this to generate a QR code\n    // data.backupCodes - Display these to the user for safekeeping\n  }\n};\n\n\nImportant: The twoFactorEnabled flag on the user is not set to true until the user successfully verifies their first TOTP code. This ensures users have properly configured their authenticator app before 2FA is fully active.\n\nSkipping Initial Verification\n\nIf you want to enable 2FA immediately without requiring verification, set skipVerificationOnEnable:\n\ntwoFactor({\n  skipVerificationOnEnable: true, // Not recommended for most use cases\n});\n\n\nNote: This is generally not recommended as it doesn't confirm the user has successfully set up their authenticator app.\n\nTOTP (Authenticator App)\n\nTOTP generates time-based codes using an authenticator app (Google Authenticator, Authy, etc.). Codes are valid for 30 seconds by default.\n\nDisplaying the QR Code\n\nUse the TOTP URI to generate a QR code for users to scan:\n\nimport QRCode from \"react-qr-code\";\n\nconst TotpSetup = ({ totpURI }: { totpURI: string }) => {\n  return <QRCode value={totpURI} />;\n};\n\nVerifying TOTP Codes\n\nBetter Auth accepts codes from one period before and one after the current time, accommodating minor clock differences between devices:\n\nconst verifyTotp = async (code: string) => {\n  const { data, error } = await authClient.twoFactor.verifyTotp({\n    code,\n    trustDevice: true, // Optional: remember this device for 30 days\n  });\n};\n\nTOTP Configuration Options\ntwoFactor({\n  totpOptions: {\n    digits: 6, // 6 or 8 digits (default: 6)\n    period: 30, // Code validity period in seconds (default: 30)\n  },\n});\n\nOTP (Email/SMS)\n\nOTP sends a one-time code to the user's email or phone. You must implement the sendOTP function to deliver codes.\n\nConfiguring OTP Delivery\nimport { betterAuth } from \"better-auth\";\nimport { twoFactor } from \"better-auth/plugins\";\nimport { sendEmail } from \"./email\";\n\nexport const auth = betterAuth({\n  plugins: [\n    twoFactor({\n      otpOptions: {\n        sendOTP: async ({ user, otp }, ctx) => {\n          await sendEmail({\n            to: user.email,\n            subject: \"Your verification code\",\n            text: `Your code is: ${otp}`,\n          });\n        },\n        period: 5, // Code validity in minutes (default: 3)\n        digits: 6, // Number of digits (default: 6)\n        allowedAttempts: 5, // Max verification attempts (default: 5)\n      },\n    }),\n  ],\n});\n\nSending and Verifying OTP\n// Request an OTP to be sent\nconst sendOtp = async () => {\n  const { data, error } = await authClient.twoFactor.sendOtp();\n};\n\n// Verify the OTP code\nconst verifyOtp = async (code: string) => {\n  const { data, error } = await authClient.twoFactor.verifyOtp({\n    code,\n    trustDevice: true,\n  });\n};\n\nOTP Storage Security\n\nConfigure how OTP codes are stored in the database:\n\ntwoFactor({\n  otpOptions: {\n    storeOTP: \"encrypted\", // Options: \"plain\", \"encrypted\", \"hashed\"\n  },\n});\n\n\nFor custom encryption:\n\ntwoFactor({\n  otpOptions: {\n    storeOTP: {\n      encrypt: async (token) => myEncrypt(token),\n      decrypt: async (token) => myDecrypt(token),\n    },\n  },\n});\n\nBackup Codes\n\nBackup codes provide account recovery when users lose access to their authenticator app or phone. They are generated automatically when 2FA is enabled.\n\nDisplaying Backup Codes\n\nAlways show backup codes to users when they enable 2FA:\n\nconst BackupCodes = ({ codes }: { codes: string[] }) => {\n  return (\n    <div>\n      <p>Save these codes in a secure location:</p>\n      <ul>\n        {codes.map((code, i) => (\n          <li key={i}>{code}</li>\n        ))}\n      </ul>\n    </div>\n  );\n};\n\nRegenerating Backup Codes\n\nWhen users need new codes, regenerate them (this invalidates all previous codes):\n\nconst regenerateBackupCodes = async (password: string) => {\n  const { data, error } = await authClient.twoFactor.generateBackupCodes({\n    password,\n  });\n  // data.backupCodes contains the new codes\n};\n\nUsing Backup Codes for Recovery\nconst verifyBackupCode = async (code: string) => {\n  const { data, error } = await authClient.twoFactor.verifyBackupCode({\n    code,\n    trustDevice: true,\n  });\n};\n\n\nNote: Each backup code can only be used once and is removed from the database after successful verification.\n\nBackup Code Configuration\ntwoFactor({\n  backupCodeOptions: {\n    amount: 10, // Number of codes to generate (default: 10)\n    length: 10, // Length of each code (default: 10)\n    storeBackupCodes: \"encrypted\", // Options: \"plain\", \"encrypted\"\n  },\n});\n\nHandling 2FA During Sign-In\n\nWhen a user with 2FA enabled signs in, the response includes twoFactorRedirect: true:\n\nconst signIn = async (email: string, password: string) => {\n  const { data, error } = await authClient.signIn.email(\n    {\n      email,\n      password,\n    },\n    {\n      onSuccess(context) {\n        if (context.data.twoFactorRedirect) {\n          // Redirect to 2FA verification page\n          window.location.href = \"/2fa\";\n        }\n      },\n    }\n  );\n};\n\nServer-Side 2FA Detection\n\nWhen using auth.api.signInEmail on the server, check for 2FA redirect:\n\nconst response = await auth.api.signInEmail({\n  body: {\n    email: \"user@example.com\",\n    password: \"password\",\n  },\n});\n\nif (\"twoFactorRedirect\" in response) {\n  // Handle 2FA verification\n}\n\nTrusted Devices\n\nTrusted devices allow users to skip 2FA verification on subsequent sign-ins for a configurable period.\n\nEnabling Trust on Verification\n\nPass trustDevice: true when verifying 2FA:\n\nawait authClient.twoFactor.verifyTotp({\n  code: \"123456\",\n  trustDevice: true,\n});\n\nConfiguring Trust Duration\ntwoFactor({\n  trustDeviceMaxAge: 30 * 24 * 60 * 60, // 30 days in seconds (default)\n});\n\n\nNote: The trust period refreshes on each successful sign-in within the trust window.\n\nSecurity Considerations\nSession Management\n\nDuring the 2FA flow:\n\nUser signs in with credentials\nSession cookie is removed (not yet authenticated)\nA temporary two-factor cookie is set (default: 10-minute expiration)\nUser verifies via TOTP, OTP, or backup code\nSession cookie is created upon successful verification\n\nConfigure the two-factor cookie expiration:\n\ntwoFactor({\n  twoFactorCookieMaxAge: 600, // 10 minutes in seconds (default)\n});\n\nRate Limiting\n\nBetter Auth applies built-in rate limiting to all 2FA endpoints (3 requests per 10 seconds). For OTP verification, additional attempt limiting is applied:\n\ntwoFactor({\n  otpOptions: {\n    allowedAttempts: 5, // Max attempts per OTP code (default: 5)\n  },\n});\n\nEncryption at Rest\nTOTP secrets are encrypted using symmetric encryption with your auth secret\nBackup codes are stored encrypted by default\nOTP codes can be configured for plain, encrypted, or hashed storage\nConstant-Time Comparison\n\nBetter Auth uses constant-time comparison for OTP verification to prevent timing attacks.\n\nCredential Account Requirement\n\nTwo-factor authentication can only be enabled for credential (email/password) accounts. For social accounts, it's assumed the provider already handles 2FA.\n\nDisabling 2FA\n\nAllow users to disable 2FA with password confirmation:\n\nconst disable2FA = async (password: string) => {\n  const { data, error } = await authClient.twoFactor.disable({\n    password,\n  });\n};\n\n\nNote: When 2FA is disabled, trusted device records are revoked.\n\nComplete Configuration Example\nimport { betterAuth } from \"better-auth\";\nimport { twoFactor } from \"better-auth/plugins\";\nimport { sendEmail } from \"./email\";\n\nexport const auth = betterAuth({\n  appName: \"My App\",\n  plugins: [\n    twoFactor({\n      // TOTP settings\n      issuer: \"My App\",\n      totpOptions: {\n        digits: 6,\n        period: 30,\n      },\n      // OTP settings\n      otpOptions: {\n        sendOTP: async ({ user, otp }) => {\n          await sendEmail({\n            to: user.email,\n            subject: \"Your verification code\",\n            text: `Your code is: ${otp}`,\n          });\n        },\n        period: 5,\n        allowedAttempts: 5,\n        storeOTP: \"encrypted\",\n      },\n      // Backup code settings\n      backupCodeOptions: {\n        amount: 10,\n        length: 10,\n        storeBackupCodes: \"encrypted\",\n      },\n      // Session settings\n      twoFactorCookieMaxAge: 600, // 10 minutes\n      trustDeviceMaxAge: 30 * 24 * 60 * 60, // 30 days\n    }),\n  ],\n});"
  },
  "trust": {
    "sourceLabel": "tencent",
    "provenanceUrl": "https://clawhub.ai/StevenFengLi/twofactor",
    "publisherUrl": "https://clawhub.ai/StevenFengLi/twofactor",
    "owner": "StevenFengLi",
    "version": "0.1.0",
    "license": null,
    "verificationStatus": "Indexed source record"
  },
  "links": {
    "detailUrl": "https://openagent3.xyz/skills/twofactor",
    "downloadUrl": "https://openagent3.xyz/downloads/twofactor",
    "agentUrl": "https://openagent3.xyz/skills/twofactor/agent",
    "manifestUrl": "https://openagent3.xyz/skills/twofactor/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/twofactor/agent.md"
  }
}