{"id":343628,"date":"2026-08-24T06:58:17","date_gmt":"2026-08-24T06:58:17","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/user-email-verification\/"},"modified":"2026-08-24T09:29:39","modified_gmt":"2026-08-24T09:29:39","slug":"shivweb-login-verification","status":"publish","type":"plugin","link":"https:\/\/wordpress.org\/plugins\/shivweb-login-verification\/","author":20940984,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.0.0","stable_tag":"1.0.0","tested":"7.1","requires":"7.0","requires_php":"8.2","requires_plugins":null,"header_name":"ShivWeb Login Verification","header_author":"Shiv Web","header_description":"Requires an email one time code after login, by user role, on WordPress and WooCommerce, including the block checkout.","assets_banners_color":"cc2261","last_updated":"2026-08-24 09:29:39","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"","header_author_uri":"https:\/\/shivweb.com\/","rating":0,"author_block_rating":0,"active_installs":0,"downloads":53,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.0.0":{"tag":"1.0.0","author":"shivweb","date":"2026-08-24 09:29:39"}},"upgrade_notice":[],"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3663006,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3663006,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256},"icon.svg":{"filename":"icon.svg","revision":3663006,"resolution":false,"location":"assets","locale":false}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3663006,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3663006,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.0.0"],"block_files":[],"assets_screenshots":[],"screenshots":[]},"plugin_section":[],"plugin_tags":[18971,1229,9210,1909,286],"plugin_category":[45,54],"plugin_contributors":[277176],"plugin_business_model":[],"class_list":["post-343628","plugin","type-plugin","status-publish","hentry","plugin_tags-email-verification","plugin_tags-login-security","plugin_tags-otp","plugin_tags-two-factor-authentication","plugin_tags-woocommerce","plugin_category-ecommerce","plugin_category-security-and-spam-protection","plugin_contributors-shivweb","plugin_committers-shivweb"],"banners":{"banner":"https:\/\/ps.w.org\/shivweb-login-verification\/assets\/banner-772x250.png?rev=3663006","banner_2x":"https:\/\/ps.w.org\/shivweb-login-verification\/assets\/banner-1544x500.png?rev=3663006","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":"https:\/\/ps.w.org\/shivweb-login-verification\/assets\/icon.svg?rev=3663006","icon":"https:\/\/ps.w.org\/shivweb-login-verification\/assets\/icon.svg?rev=3663006","icon_2x":false,"generated":false},"screenshots":[],"raw_content":"<!--section=description-->\n<p>ShivWeb Login Verification adds two-factor authentication (2FA) to your WordPress login using email codes. A user signs in with their password as usual, then the plugin emails them a short login code and holds the session until the code is entered. Someone who has stolen a password but cannot open the user's inbox stays locked out.<\/p>\n\n<p>There is no authenticator app to set up, no external service to sign up for, and no API keys. Codes are sent through your site's own email, so any SMTP plugin you already use handles delivery, and everything runs on your server.<\/p>\n\n<h4>How a login works<\/h4>\n\n<ol>\n<li>The user enters their username and password as normal.<\/li>\n<li>The plugin emails them a one time code (OTP) and holds the session.<\/li>\n<li>They type the code on the verification screen and continue exactly where they were going.<\/li>\n<\/ol>\n\n<h4>Choose who needs a code<\/h4>\n\n<p>Enforcement is role based. Tick the roles that should verify and leave the rest alone. By default only the Customer role is gated, so a store can protect shopper accounts without changing how the team logs in. Users can also mark a browser as trusted for a number of days you choose, so regulars are not asked for a code on every visit.<\/p>\n\n<h4>Built so you cannot lock yourself out<\/h4>\n\n<p>Enforcement stays off until you prove email delivery works: the plugin asks you to send yourself a test code and enter it before the feature can be switched on. So a broken mailer can never lock everyone out. And if anything ever goes wrong later, one line in wp-config.php or one WP-CLI command turns everything off and releases every held session immediately.<\/p>\n\n<h4>Works with WooCommerce, including the block checkout<\/h4>\n\n<p>Most login verification plugins add a field to the login form. The WooCommerce block checkout never shows that field, because it signs customers in through the Store API in the background. This plugin works differently: it verifies the session after login, on the server, so wp-login.php, wp-admin, My Account, the classic checkout and the block checkout are all covered by the same check. Nothing depends on the browser, so it cannot be skipped by calling an endpoint directly.<\/p>\n\n<h4>Email verification at registration<\/h4>\n\n<p>Optionally require new sign-ups to confirm their email address with a code before their first session works. A small popup verifies the address right on the register form, checkout registrations are verified just after, and abandoned unverified accounts are cleaned up automatically after a grace period.<\/p>\n\n<h4>Features<\/h4>\n\n<ul>\n<li>Two-factor authentication with email login codes, no authenticator app needed<\/li>\n<li>Role based enforcement: choose exactly which user roles must verify<\/li>\n<li>WooCommerce ready: My Account, classic checkout, and the block checkout<\/li>\n<li>Trusted devices: remember a browser for a number of days you choose<\/li>\n<li>Email verification for new registrations, with automatic cleanup<\/li>\n<li>Rate limiting on every layer: resend cooldown, attempt lockout, and per-account send caps<\/li>\n<li>Customizable email template and on-screen messages<\/li>\n<li>No external service, no API keys, no per-message fees, no tracking<\/li>\n<li>Recovery built in: a wp-config.php constant and WP-CLI commands<\/li>\n<\/ul>\n\n<h4>Recovery<\/h4>\n\n<p>If you ever lock yourself out, add <code>define( 'SWLV_DISABLE_OTP', true );<\/code> to wp-config.php, or run <code>wp swlv disable<\/code> with WP-CLI. Both release every held session immediately. To unstick a single user (send limit reached, mailbox typo), run <code>wp swlv reset-user &lt;id|login|email&gt;<\/code>.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Install and activate the plugin. Nothing is enforced yet.<\/li>\n<li>Go to Settings, then Email Verification.<\/li>\n<li>Choose the roles that should verify, send yourself a test code, enter it, tick \"Require a code at login\", and save.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"is%20this%20two-factor%20authentication%3F\"><h3>Is this two-factor authentication?<\/h3><\/dt>\n<dd><p>Yes, the email variant: the password is something the user knows, and the code proves control of their mailbox. It is the same email method WordPress's own Two-Factor plugin offers. An authenticator app is stronger in the strict sense, but an email code still stops anyone who only has the password, which is how most accounts are broken into.<\/p><\/dd>\n<dt id=\"does%20it%20work%20with%20the%20woocommerce%20block%20checkout%3F\"><h3>Does it work with the WooCommerce block checkout?<\/h3><\/dt>\n<dd><p>Yes. The block checkout logs customers in over the Store API, which the plugin refuses for unverified sessions, and a small script guides the shopper to the verification screen.<\/p><\/dd>\n<dt id=\"does%20it%20send%20email%20through%20its%20own%20service%3F\"><h3>Does it send email through its own service?<\/h3><\/dt>\n<dd><p>No. All email goes through wp_mail(). Use any SMTP plugin you like for reliable delivery.<\/p><\/dd>\n<dt id=\"what%20happens%20if%20email%20delivery%20breaks%20after%20i%20enable%20it%3F\"><h3>What happens if email delivery breaks after I enable it?<\/h3><\/dt>\n<dd><p>Affected users cannot verify, but you can always recover with the wp-config.php constant or WP-CLI, both documented above. Administrators are not gated by default.<\/p><\/dd>\n<dt id=\"the%20code%20email%20is%20not%20arriving.%20what%20should%20i%20check%3F\"><h3>The code email is not arriving. What should I check?<\/h3><\/dt>\n<dd><p>Check the spam folder first. The screen lets you request a new code after a short cooldown. If nothing arrives at all, the site's email delivery is the usual cause: the site owner can go to Settings, then Email Verification, and send themselves a test code. If that fails too, install an SMTP plugin and test again. A single stuck user can always be released with <code>wp swlv reset-user<\/code>.<\/p><\/dd>\n<dt id=\"i%20enabled%20it%2C%20but%20nobody%20is%20asked%20for%20a%20code\"><h3>I enabled it, but nobody is asked for a code<\/h3><\/dt>\n<dd><p>Three things are expected behavior here. Sessions that were already logged in before you enabled enforcement are never challenged, only new logins are. A browser remembered through \"Trust this device\" skips the code until the trust expires. And only the roles you ticked are gated, so check the role of the account you are testing with, and note that administrators are not gated by default.<\/p><\/dd>\n<dt id=\"what%20data%20does%20the%20plugin%20store%3F\"><h3>What data does the plugin store?<\/h3><\/dt>\n<dd><p>Codes are never stored, not even hashed alone: only keyed hashes live inside the WordPress session record, and they disappear when the session ends. Beyond that the plugin keeps one settings option, per-user send counters and trusted-device hashes in user meta, short-lived self-expiring transients for registration challenges and rate limits, and one cookie for \"Trust this device\". There are no external services and nothing leaves your site. Uninstalling removes all of it. On shared computers, leave \"Trust this device\" unticked.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>Initial release.<\/li>\n<\/ul>","raw_excerpt":"Two-factor authentication by email code. Users log in with their password, then enter a login code from their inbox. WooCommerce ready.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/343628","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=343628"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/shivweb"}],"wp:attachment":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=343628"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=343628"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=343628"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=343628"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=343628"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=343628"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}