WP Manifestindependent plugin directory
manifest / security / bricks-2fa-bridge

Bricks 2FA Bridge

Makes Bricks Builder login forms work with your two-factor authentication plugin.

by Matt Bosak · github.com/mattbosak/bricks-2fa-bridge · website

8stars
0forks

Install

No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:

wp plugin install https://github.com/mattbosak/bricks-2fa-bridge/archive/refs/heads/main.zip

Makes Bricks Builder login forms work with your two-factor authentication plugin. Your users enter their 2FA code in a field right on your custom login form - no page reload, no broken logins, no bypassed second factor.

Setup is quick. Install the plugin, add one field to your existing login form, and you're done - most people are up and running in a few minutes, with no separate settings screen to configure.

If it saves you an afternoon, you can buy me a coffee. Entirely optional - the plugin is free and GPL either way.

Contents

What it fixes

Bricks' Form element has a "User Login" action for building custom login pages. Combine it with a 2FA plugin and the login breaks in one of two ways:

  • It fails silently - no error, no code prompt, no login. The spinner just stops.
  • Or the second factor is skipped entirely - the account logs in the moment the password checks out, 2FA or not.

Both come from the same root cause. Most 2FA plugins expect a full-page form submission, and respond to a pending second factor by printing a challenge page and exiting - which Bricks' AJAX request can't parse. Bricks, meanwhile, completes the login the moment wp_signon() succeeds, without checking whether a 2FA plugin still wants a say. This plugin closes both gaps: it intercepts WordPress's own authenticate filter before any 2FA plugin runs, so a pending second factor can never be bypassed, and it moves code entry onto your own login form, so nothing ever tries to render a challenge page inside the AJAX request.

How it looks to your users

  1. They enter username and password on your Bricks login form, as always.
  2. If their account has 2FA, a code field appears on the same form (it stays hidden for everyone else), with a hint like "Check your email for a code."
  3. They enter the code and submit again - logged in, never having left the page.

The code field is one you add in the Bricks builder yourself, so it inherits your form's styling like any other field.

Requirements

Installation

  1. Install and activate a supported 2FA plugin (list above), if you haven't already.

  2. Install this plugin: download the latest release zip and upload it under Plugins → Add New → Upload Plugin, then activate.

  3. Add the code field to your login form in the Bricks builder:

    • Add a Text field.
    • Set Attribute: Name (in the field's own settings panel, under Attributes) to exactly b2fa_code.
    • Leave Required off.

    The field needs to be submittable empty on the first attempt, since the plugin doesn't know a code is needed until then - and once added, it stays hidden until a login actually needs one.

  4. Optional - add a method selector, to let users choose between their enabled 2FA methods (e.g. Authenticator App / Email / Backup Codes) instead of always using their primary one:

    • Add a Select field with Attribute: Name set to exactly b2fa_method.
    • Set its Options to one line, e.g. Loading methods… - just avoid the literal words totp, email, or backup_codes.

    Bricks won't render a <select> field at all if its Options list is empty, which is why one placeholder line is required - this plugin replaces it with the real options before a user ever sees it, so the placeholder text itself doesn't matter. It does matter that it isn't totp, email, or backup_codes, though: those are real method ids, and using one as the placeholder would pre-select that specific method instead of correctly falling back to the primary one.

    Skip this field entirely and everyone simply uses their primary method.

FAQ

General

Does this plugin provide two-factor authentication itself? No. It's a compatibility bridge - it makes your existing 2FA plugin work correctly with Bricks' AJAX login forms.

Does it work with a custom "Login error message" set on my form? Yes. The reveal signal travels via an HTTP response header, independent of whatever message text Bricks displays.

Do brute-force protections still apply? Yes. Code attempts through the form get an increasing delay after each failure plus a hard attempt ceiling (both filterable - see below), failures still feed your security plugin's own counters where it keeps them, and where the 2FA plugin has its own protection (like Two-Factor's compromised-password reset), that fires too.

A user has a passkey - can they log in through the Bricks form? No, and they are told so rather than left guessing. A passkey is a browser-side WebAuthn exchange that cannot be completed by typing a code into a form field, so those users see a message asking them to contact the site administrator. They can still log in through the normal WordPress login screen. The same applies to any method a future 2FA plugin release adds that this bridge does not yet drive.

The form asks for a code but there is nowhere to type it. Almost always the Text field is missing from the form, or its Name attribute is not exactly b2fa_code - the plugin only activates on a submission carrying that field. If the field is correct and the form still will not progress, the next likeliest cause is a security plugin, proxy or CDN stripping the response headers this plugin uses to signal that a code is required; enable WP_DEBUG and look for a bricks-2fa-bridge entry in the error log.

Plugin-specific notes

What if I run two supported 2FA plugins at once? It works - this mainly matters mid-migration between 2FA plugins. Each user is challenged by the first plugin (in the order Two-Factor, WP 2FA, Wordfence, Kadence Security, AIOS/Simba) that has 2FA enabled for them - one code per login, and the other plugin won't double-challenge or break the response. A plugin that doesn't consider someone a 2FA user keeps all its own policies for them.

I use Kadence Security - what about its other login interstitials? Only the two-factor step is bridged into the Bricks form. Kadence's other interstitials (e.g. a forced password change) are separate features and keep their normal behavior.

I use AIOS or the Two Factor Authentication plugin - does "trust this device" work?

  • Existing trusted devices: honored - a trusted browser skips the code, same as upstream.
  • Marking a new device as trusted: not possible from a Bricks form - users do that once via wp-login.php.

I use WP 2FA with enforced 2FA - what about users who haven't set it up yet?

  • Users with 2FA configured: work fully through the Bricks form.
  • Users enforced but not yet configured: get WP 2FA's setup-wizard redirect, which can't render inside an AJAX login - they complete their one-time setup via wp-login.php, and the Bricks form works for them from then on.

I use Wordfence's login CAPTCHA - does that work with a Bricks login form?

  • With 2FA active: yes - a valid code satisfies the login, mirroring Wordfence's own rule that a valid 2FA code exempts the CAPTCHA check.
  • Without 2FA: Wordfence falls back to its email verification link (a Bricks form has no reCAPTCHA integration) - that's Wordfence's own behavior, unchanged by this plugin.

For developers

If a user's only second factor is one the form cannot complete - a passkey, or a provider added by another plugin - they are shown "Your two-factor authentication method cannot be completed on this login form. Please contact the site administrator." rather than a code box that can never be satisfied. The bricks_tfa_bridge_unsupported_method action fires so you can log or alert on it; with WP_DEBUG on, a line also goes to the error log. Such a user can still log in through your site's normal WordPress login screen.

Filters, all optional:

Hook Purpose Default
bricks_tfa_bridge_code_field_id POST name of the code field b2fa_code
bricks_tfa_bridge_method_field_id POST name of the method selector b2fa_method
bricks_tfa_bridge_header_name Header signaling "code required" X-Bricks-TFA-Required
bricks_tfa_bridge_methods_header_name Header carrying the methods list X-Bricks-TFA-Methods
bricks_tfa_bridge_base_delay Backoff base, in seconds (delay = base × 2ⁿ) 1 or adapter value
bricks_tfa_bridge_max_delay Backoff cap, in seconds 15 min or adapter value
bricks_tfa_bridge_failed_attempt_limit Hard ceiling on total failures 30 or adapter value
bricks_tfa_bridge_adapters Register custom adapters built-in adapters

The bricks_tfa_bridge_attempt_limit_reached action fires when a user hits the hard failure ceiling, in case you want to notify someone.

Support for another 2FA plugin is one class implementing src/AdapterInterface.php, registered via the bricks_tfa_bridge_adapters filter. Read CLAUDE.md first - it documents the architecture, the per-plugin gotchas already solved, and the source-verification process each existing adapter went through.

Compiled .mo files are not committed; they are built from the .po sources during release. Installing from a clone therefore gives you an untranslated (English) plugin until you run msgfmt over languages/*.po yourself. Use a release zip for anything other than development.

Support the project

This plugin is free and always will be. If it saved you time, a coffee is a nice way to say so: ko-fi.com/mattbosak.

Bug reports and pull requests are just as welcome, and cost nothing.

License

GPLv2 or later. See the license header in bricks-2fa-bridge.php.