Black Friday: 50% off. Your first year on any annual plan, until 1 December. See the dealFirst year on annual plans, until 1 December
WPClientHub V2 is live. Fewer plugins on your client sites: caching, forms and image optimization now come built into WPClientHub One. See what’s newCaching, forms and images, built in. See what’s new
Sign in Start free

← Docs  /  Reference

Security & data

Updated 2026-10-08

Magic links, two-factor auth and sessions, exactly what WPClientHub One can and can't do, where private keys live, and how the database is protected.

Browse documentation

What it does

This page collects the security facts that matter most when you're deciding whether to trust WPClientHub with a client site.

  • Client sign-in links: 15 minutes, single-use, throttled 5 attempts per email / 20 per IP per 15 minutes, enumeration-safe (a known and an unknown email get the identical response).
  • Client invitation links: 7 days, single-use.
  • Team invitation links: 7 days, single-use, with a reminder email 48 hours after sending.
  • Every magic link is stored hashed, never in plaintext, and is never queued for delivery — it is sent synchronously so the plaintext token never touches a queue backend.

What the WPClientHub One plugin can and can't do

Pairing a site gives your WPClientHub account administrative control over that site: syncing state, running updates you trigger, taking backups, one-time single-use login, toggling maintenance mode, and — from plugin version 0.5.0 — updating itself when you ask it to. It never auto-applies anything without you asking, including security releases; a security release is flagged urgent, never installed silently.

When you pair a site, WPClientHub generates a unique Ed25519 keypair for that site. The site receives and stores only the public key; the private signing key stays with WPClientHub, encrypted (see where the signing keys live). Every request from WPClientHub to the site carries a detached Ed25519 signature over a timestamp, a random nonce, and the exact request body, verified with libsodium before anything runs; requests more than 5 minutes off, or replayed nonces, are rejected outright. For data a site pushes back (sync results, activity log entries), the site generates its own bearer secret at pairing time — WPClientHub never chooses a site's own credentials.

Your WordPress password is never seen, stored, or transmitted by WPClientHub. One-click login uses a single-use, 60-second token instead. The one exception is a password you explicitly ask a site to generate for a new account in WordPress user management: the site creates it, it is shown to you once in that dialog, and it is never stored by WPClientHub. The user lists we keep hold logins, emails, roles and last sign-in — never passwords or password hashes.

Google Drive & Dropbox backup destinations

When you connect your agency’s Google Drive or Dropbox as backup storage, WPClientHub asks for the narrowest access each offers — Google’s drive.file (only files WPClientHub creates) and a Dropbox App folder (only Apps/<app name>). The long-lived grant is stored encrypted and never leaves WPClientHub; each backup or restore hands the site a short-lived access token, used for an hour at most and discarded when the job ends. Archives travel from the site to Google or Dropbox directly — WPClientHub never sees what is in them. Disconnecting revokes the grant at Google or Dropbox. See Google Drive & Dropbox backups.

Where the signing keys live

Each site's private signing key is stored in WPClientHub's database, encrypted at rest (AES-256) with the application's encryption key. That key is kept in the server's configuration, not in the database, and is never written into a database backup. The token a site uses to send data back, and every pairing token, are stored only as SHA-256 hashes. The other credentials you connect (Stripe restricted keys, backup storage, Search Console and Cloudflare tokens) and two-factor secrets are encrypted the same way.

If WPClientHub itself were breached

What an attacker could do depends on what they get:

  • A copy of the database only, for example a leaked backup file. The signing keys in it are encrypted and useless without the application key, which isn't in the database. Tokens are hashes that can't be turned back into tokens. The backup file is itself encrypted with a separate key. A copy of the database can't be used to control a site.
  • The whole WPClientHub server, database and application key together. An attacker could decrypt the signing keys and send signed requests to connected sites, with the same reach you have from the dashboard: updates, backups and restores, single-use logins and WordPress user changes. That is the scenario our server security is built around, and we would rather say so than call a breach harmless.

What limits the damage, and what you can do:

  • Per-site keys. Every site has its own key pair, so a key only ever works on that one site.
  • Signed requests with replay protection. Each request is signed over a timestamp, a random nonce and the exact body. A request more than 5 minutes old, or one seen before, is refused, so an intercepted request can't be reused.
  • Revocation on the site. Disconnect on the WPClientHub One settings page deletes the site's copy of the public key, so no signature, old or stolen, is accepted again; deactivating the plugin stops it answering at all. Reconnect in WPClientHub issues a new key pair for the site, and the old one stops working the moment the site completes the handshake. Removing a site from the WPClientHub dashboard revokes its sync token but leaves the key on the site, so use the plugin's Disconnect, or Reconnect, to revoke the key itself.

Backups of the hub itself

WPClientHub's own database — the one holding every managed site's encrypted signing key and your account data — is backed up daily, encrypted, and verified every night by a test restore into a scratch database. An hourly check confirms the newest backup is fresh and encrypted, and emails us the moment it isn't.

Two-factor authentication

Any member can turn on two-factor authentication (TOTP — Google Authenticator, 1Password, Authy, any RFC 6238 app) from Settings → Security: scan a QR code, confirm the current six-digit code, and it's on. Ten single-use recovery codes are issued at that moment and shown exactly once — save them somewhere safe, since a lost phone with no saved codes means asking an owner or admin to remove and re-invite the account. Codes can be regenerated at any time, which invalidates the old set.

An owner can require two-factor authentication for everyone in the organization from the same page. Turning that on is refused unless the owner turning it on is themselves enrolled — otherwise a single-owner organization could lock out its only owner. A member caught by the requirement without two-factor on is redirected to Security to set it up on their very next request; nothing already open in their browser is interrupted or logged out.

Turning two-factor off, regenerating recovery codes, and signing out other sessions all require a fresh re-confirmation of your password (and, once enrolled, your second factor too) taken within the last ten minutes — the same "confirm it's you" prompt Laravel calls step-up re-authentication, just enforced on more than the one route it ships with by default.

Active sessions

Settings → Security also lists every browser currently signed in to your account — device/browser, IP address, and when it was last active — pulled directly from the session store, and lets you sign out every session except the one you're using right now. Changing your password does the same thing automatically: it invalidates every other session's "remember me" cookie and removes their session rows outright, so a stolen password stops being useful the moment you notice and change it.

Limits & defaults

SettingDefault
Client magic link TTL15 minutes
Client / team invite TTL7 days
Request signature clock skew tolerance5 minutes
One-click login tokenSingle-use, 60 seconds
Site signing keysEd25519, one pair per site; private key encrypted at rest (AES-256); replaced on every Reconnect
Hub database backupDaily, encrypted, test-restored nightly, freshness-checked hourly
Google Drive / Dropbox grantEncrypted at rest, never sent to a site; sites get one-job access tokens used for an hour at most
Two-factor recovery codes10, single-use, regenerate any time
Two-factor code window±30 seconds, each code usable once
Two-factor code attempts5 per minute, per account and per IP
"Remember this device" at login30 days, opt-in per device
Step-up re-confirmation window10 minutes

Troubleshooting

Is my WordPress password ever stored by WPClientHub?
No. Never. Authentication with a site is purely cryptographic; login uses one-time tokens.
What happens if WPClientHub's own database were breached?
A copy of the database alone holds each site's private signing key only in encrypted form, unusable without the application key, which is kept outside the database and out of its backups, plus token hashes that can't be reversed. A full compromise of the server, database and application key together, could be used to send signed requests to connected sites. That is why keys are per site and can be revoked from the site with Disconnect, or replaced with Reconnect. See If WPClientHub itself were breached.
I lost my phone and have no recovery codes left
Ask an owner or admin in your organization to remove your account from Team and invite you again — nothing about your organization's sites, clients or history is affected.
My organization requires two-factor and I can't turn mine off
That's intentional — an owner has to lift the organization-wide requirement first, from Settings → Security, before any individual member can disable their own.