# Two-factor for WooCommerce customers: passkeys and codes

How WooCommerce customers set up two-factor and passkeys on My Account › Sign-in security with BetterShield, what you can ask of staff, and what you can’t.

By M Asif Rahman, Oct 24, 2026. Updated Nov 8, 2026.

WooCommerce customers can use two-factor and passkeys with **BetterShield** without you switching anything on: the plugin adds a **Sign-in security** tab to **My Account**, where each customer sets up an authenticator app, adds a passkey and sees where they are signed in. This guide shows what the customer sees, what you can and can’t require, and how to check it works on your store.

If you want the whole store picture first, [WooCommerce security: protect customer and staff sign-ins](/blog/woocommerce-security/) covers the bot check, the sign-in pause and staff roles. This post goes deeper on the one part customers touch themselves.

## Quick summary

- BetterShield adds **My Account › Sign-in security** to a WooCommerce store, just before **Log out**. It is in the free plugin, and nothing is added to the cart or checkout.
- A customer can turn on two-factor with any authenticator app, add up to ten passkeys and end sessions on devices they don’t recognize.
- Two-factor for customers is their choice. **Require two-factor of a role** is enforced in the dashboard, and WooCommerce keeps customers out of it, so it never reaches them.
- A passkey that the device unlocks with a fingerprint, face or PIN signs in without a code, even on an account that uses two-factor.
- Passkeys need HTTPS, and the passkey button is on the site’s own sign-in page, not on the **My Account** form.

## Why offer it at all

A customer account holds an address, an order history and sometimes a saved way to pay. A password is all that stands in front of it, and people reuse passwords. A second step, a six-digit code from an app, means a stolen password alone opens nothing. The code is a [time-based one-time password](https://en.wikipedia.org/wiki/Time-based_one-time_password) that changes every 30 seconds.

A passkey goes one step further. It is a key the customer’s device keeps and unlocks with a fingerprint, face or PIN. The site stores only the public half, there is nothing to type, and the browser offers it only to this site’s own domain. The browser feature behind it is the [Web Authentication API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Authentication_API).

Most customers will never ask for either. The point of offering them is that the customers who do want more can switch it on themselves, with no ticket to you.

## What customers see on My Account

WordPress keeps customers out of the dashboard, profile included, so a store needs another home for these controls. That home is the **Sign-in security** tab. It has the same three sections the WordPress **Profile** screen has for everyone else:

| Section | What the customer can do |
|---|---|
| **Two-factor sign-in** | Set up an authenticator app, see how many backup codes are left, issue new ones, or turn it off. |
| **Passkeys** | Add a passkey, see the list by name, remove one. |
| **Where you are signed in** | See every device signed in, most recent first, and end any of them. |

Nothing is added to the cart or the checkout. The tab shows to a signed-in customer, and links that would have pointed to the profile point here instead.

## How a customer turns on two-factor

The steps are the same ones your own team follows on a profile. A customer who asks you how can be sent this list.

1. Open **My Account › Sign-in security** and press **Set up two-factor**.
2. Scan the code with an authenticator app, or type the **Manual entry key**.
3. Enter the **Code from the app** and press **Confirm code**.
4. Save the ten backup codes with **Copy Codes** or **Download Codes**. They are shown once. If copying fails, select and copy them yourself.
5. Press **I have stored these codes**. This is the button that turns two-factor on, and nothing changes at sign-in until it is pressed.

After that, a correct password leads to an **Authenticator app code or backup code** screen on the site’s own sign-in page. The field takes the app’s current six-digit code or an unused eight-digit backup code. Each code works once.

Two limits protect the account. Each account may get 10 codes wrong in an hour; after that no code is checked until the hour is up. And a waiting sign-in expires after 10 minutes.

### When the phone is lost or replaced

A customer who still has a backup code can use **Turn off, or move to a new phone**, enter a **Code from the app, or a backup code**, and press **Turn two-factor off**. **Set it up on a new phone** then starts again. When three or fewer backup codes remain, the section suggests issuing a new set with **Issue new backup codes**, which replaces every old code at once.

A customer who has lost both the phone and the codes needs you. Open their account under **Users**; if they use two-factor, **Turn off two-factor for this account** removes it and signs the account out everywhere. They then sign in with their password alone until they set it up again. [WordPress 2FA backup codes vs recovery codes](/blog/wordpress-2fa-backup-codes/) explains the difference between the customer’s codes and your own recovery route.

## How a customer adds a passkey

On the same tab, the **Passkeys** section asks the customer to name the device, such as Work laptop, and press **Add a passkey**. The section first asks them to prove it is them: a current code or backup code if they use two-factor, otherwise their password. Then they confirm on the device.

- An account holds up to ten passkeys, so a customer can add a phone and a laptop.
- Passkeys need HTTPS. Without it, the section says why and stays switched off.
- A browser that cannot use passkeys says so, and nothing changes.
- Removing a passkey asks the same proof and signs the account out on every other device. The browser they remove it from stays signed in.

### Where the passkey button is

This is the detail that surprises people. The **Sign in with a passkey** button sits below the **Log In** button on the site’s own sign-in page, once any account on the site has a passkey. It is not on the **My Account** sign-in form or at checkout. A customer who has a passkey signs in with it on the site’s sign-in page, so it helps to link them there if you want them to use it.

How a passkey counts depends on how the device unlocked it:

| Unlocked with | Account without two-factor | Account with two-factor |
|---|---|---|
| Fingerprint, face or PIN | Signed in | Signed in, no code asked |
| Only a touch | Not accepted on its own | Goes on to the **Authenticator app code or backup code** screen |

Every other sign-in rule still applies to a passkey sign-in, including the pause after repeated failures. A passkey is an extra way in, so the customer’s password and backup codes keep working. For the full setup, [How to add passkeys to WordPress](/blog/wordpress-passkeys/) and the [Passkeys doc](/docs/passkeys/) go through it. If you later want to turn passwords off for a role, [passkey-only sign-in](/blog/wordpress-passkey-only-sign-in/) explains why a store’s customers are best left out of it.

## Where you are signed in

The third section is the one customers use most when something feels off. It lists each device with the browser and system, the network it came from, never the full address, and when it was last active. **This was not me** ends one session straight away. **Sign out everywhere except this device** ends all the others at once, and appears only while another device is signed in. A customer who doesn’t recognize a device should end it and change their password.

## What you can and can’t require

This is where store owners most often expect more than the plugin does, so it is worth being plain.

**You can’t require two-factor of customers.** **Require two-factor of a role**, under **BetterShield › Protection › Two-Factor**, is enforced inside the dashboard. WooCommerce sends customers to **My Account** instead, so the requirement never reaches them. For customers, two-factor is an offer.

**You can require it of staff.** Tick roles such as Administrator, Editor and Shop manager, leave the **Grace period, in days** at its default of 14, and press **Save requirement**. Only the app codes count toward it, not a passkey. [Require two-factor of a role, with a grace period](/docs/require-two-factor/) lists what staff see before and after the deadline.

**You can make the offer visible.** Because the feature lives on one tab, the best thing you can do is tell customers it is there: a line in your account-related emails, or on your help page, pointing to **My Account › Sign-in security**.

## What it can break, and how to undo

- **Customers who lose their codes.** They need you to turn two-factor off for the account, as above. They are never locked out of the store itself; their password works again once two-factor is off.
- **Tools that sign in with the account password.** A customer who uses two-factor cannot sign in over XML-RPC or a REST request with the password alone. An application password skips the code.
- **A shared account.** Each account holds one waiting sign-in at a time, so a second person entering the password expires the first person’s code screen. One account per person avoids it.
- **Two plugins asking.** If another security plugin also asks for a code, a customer may be asked twice. Use one plugin’s two-factor.

To undo any of it, the customer turns two-factor off or removes the passkey on the same tab, or you do it for them from **Users**. Nothing here changes your store settings.

## Check it is working

- Sign in to a test customer account and confirm **Sign-in security** appears on **My Account**, just before **Log out**.
- Set up two-factor on the test account with an authenticator app, sign out, and sign in again to see the **Authenticator app code or backup code** screen.
- Add a passkey on the test account, then look for **Sign in with a passkey** below **Log In** on the site’s sign-in page.
- Open the activity log and look for “Passkey added” and “Signed in with a passkey”.
- Place a test order. Nothing about the cart or checkout should look different.

## Recommended settings

We recommend leaving the customer side alone, since there is nothing to configure, and doing the work around it: tell customers the tab exists, require two-factor of your staff roles, and set up two-factor and a passkey on your own account first. Keep the sign-in pause and the hidden bot check at their defaults. They protect the same **My Account** forms.

## Frequently asked questions

### Can WooCommerce customers use two-factor authentication?

Yes. Each customer can set up two-factor with any authenticator app from **My Account › Sign-in security**. It is their choice; the store cannot require it of customers.

### Can customers sign in to WooCommerce with a passkey?

Yes, with a site that uses HTTPS. A customer adds a passkey on **My Account › Sign-in security** and then signs in with **Sign in with a passkey** on the site’s own sign-in page. The button is not on the **My Account** form.

### Does two-factor slow down checkout?

No. BetterShield adds nothing to the cart or checkout. Two-factor applies when a customer signs in, not when they pay.

### What if a customer loses their phone and backup codes?

An administrator opens the account under **Users** and uses **Turn off two-factor for this account**. The customer then signs in with their password alone until they set it up again.

### Do I have to switch anything on?

No. The tab is there once BetterShield is active on a WooCommerce store. You only need to decide whether to tell customers about it.

## Conclusion

Offer customers a stronger sign-in by letting them find it: **My Account › Sign-in security** already holds two-factor, passkeys and a device list. Require two-factor of your staff, who reach orders and customer details, and leave the choice to customers.

BetterShield is free on [WordPress.org](https://wordpress.org/plugins/bettershield/). The docs cover each part: [Two-factor and passkeys](/docs/two-factor-and-passkeys/), [Your profile](/docs/your-profile/) and [Passkeys](/docs/passkeys/). The [WooCommerce use case](/use-cases/woocommerce/) shows the whole picture for a store.
