Title: AuthDock — Login Security, 2FA, Social Login &amp; Brute Force Protection
Author: RAKIBUZZAMAN
Published: <strong>9 Meán an tSamhraidh, 2026</strong>
Last modified: 5 Meán Fómhair, 2026

---

Search plugins

![](https://ps.w.org/authdock/assets/banner-772x250.png?rev=3682601)

![](https://ps.w.org/authdock/assets/icon-256x256.png?rev=3566239)

# AuthDock — Login Security, 2FA, Social Login & Brute Force Protection

 By [RAKIBUZZAMAN](https://profiles.wordpress.org/rakibantor/)

[Download](https://downloads.wordpress.org/plugin/authdock.2.1.6.zip)

 * [Details](https://ga.wordpress.org/plugins/authdock/#description)
 * [Reviews](https://ga.wordpress.org/plugins/authdock/#reviews)
 *  [Installation](https://ga.wordpress.org/plugins/authdock/#installation)
 * [Development](https://ga.wordpress.org/plugins/authdock/#developers)

 [Support](https://wordpress.org/support/plugin/authdock/)

## Description

**AuthDock** is one authentication plugin instead of five: social login, magic links,
passkeys, two-factor authentication, brute-force protection, audit logging, session
control and wp-admin access rules — with a WordPress-native UI, a REST API, and 
nothing phoning home.

Every feature ships switched off; turning one on is your decision. There is no telemetry,
no licence check and no upsell, and with everything off the plugin makes no outbound
request at all.

Every form is a shortcode, a block and a theme-overridable template, so the login,
registration, password-reset and account screens can live anywhere in your theme.

The feature list is below. What each feature does and does not send to a third party
is under **External services**; what is stored, and for how long, is under **Privacy**.

### External services

AuthDock contacts a third-party service only where you have switched on a feature
that
 needs one, and never otherwise. There is no telemetry, no usage reporting,
no licence check, and no phone-home of any kind. Every feature below is off by default,
and with all of them off the plugin makes no outbound request at all.

Ten features can talk to somebody else’s server. Each is listed here with what is
sent,
 when, and to whom.

#### 1. Social Login

**When:** a provider is configured with your own OAuth credentials and a visitor
clicks its
 sign-in button.

Clicking a provider’s button redirects the visitor’s browser to
 that provider, 
carrying the client ID you configured, the redirect URL back to your site, the requested
scopes, and a single-use state and PKCE challenge. Your site then makes one server-
to-server request to exchange the returned code for an access token, and one to 
read the profile it grants. AuthDock reads only the account ID, display name, email
address, email-verified flag, and avatar URL from that profile, and sends the provider
nothing about your site or its other users.

If no provider is enabled, none of this runs.

 * **Google OAuth** — `accounts.google.com`, `oauth2.googleapis.com`, `www.googleapis.
   com` — [Terms](https://policies.google.com/terms) | [Privacy](https://policies.google.com/privacy)
 * **Facebook Login** — `www.facebook.com`, `graph.facebook.com` — [Terms](https://www.facebook.com/legal/terms)
   | [Privacy](https://www.facebook.com/privacy/policy/)
 * **GitHub OAuth** — `github.com`, `api.github.com` — [Terms](https://docs.github.com/en/site-policy/github-terms/github-terms-of-service)
   | [Privacy](https://docs.github.com/en/site-policy/privacy-policies/github-general-privacy-statement)
 * **X (Twitter) OAuth** — `twitter.com`, `api.twitter.com` — [Terms](https://x.com/en/tos)
   | [Privacy](https://x.com/en/privacy)
 * **Sign in with Apple** — `appleid.apple.com` — [Terms](https://www.apple.com/legal/internet-services/)
   | [Privacy](https://www.apple.com/legal/privacy/)
 * **Microsoft / Entra ID** — `login.microsoftonline.com`, `graph.microsoft.com`—
   [Terms](https://www.microsoft.com/servicesagreement) | [Privacy](https://privacy.microsoft.com/privacystatement)
 * **LinkedIn** — `www.linkedin.com`, `api.linkedin.com` — [Terms](https://www.linkedin.com/legal/user-agreement)
   | [Privacy](https://www.linkedin.com/legal/privacy-policy)
 * **Discord** — `discord.com` — [Terms](https://discord.com/terms) | [Privacy](https://discord.com/privacy)
 * **Twitch** — `id.twitch.tv`, `api.twitch.tv` — [Terms](https://www.twitch.tv/p/legal/terms-of-service/)
   | [Privacy](https://www.twitch.tv/p/legal/privacy-notice/)
 * **Slack** — `slack.com` — [Terms](https://slack.com/terms-of-service) | [Privacy](https://slack.com/trust/privacy/privacy-policy)

Apple is the one that behaves differently: it returns the account holder’s name 
once, in the
 form POST of the very first sign-in and never again, and it offers
a relay address ending @privaterelay.appleid.com in place of a real one. AuthDock
stores the name on that first sign-in because there is no second chance, and treats
a relay address as a real address.

#### 2. Bot Protection, when a CAPTCHA provider is selected

**When:** Bot Protection is enabled _and_ its provider is set to Turnstile, hCaptcha
or
 reCAPTCHA. The default provider is **Proof of work**, which runs entirely in
the visitor’s browser and contacts nobody.

With a CAPTCHA provider selected, the visitor’s browser loads that provider’s script,
and
 the provider sets and reads its own cookies under its own domain. When the 
form is submitted, your site makes one server-to-server request to the provider’s
verify endpoint carrying the secret key you configured, the token the widget produced,
and the visitor’s IP address. Nothing about the account being signed into is sent.

 * **Cloudflare Turnstile** — `challenges.cloudflare.com` — [Terms](https://www.cloudflare.com/website-terms/)
   | [Privacy](https://www.cloudflare.com/privacypolicy/)
 * **hCaptcha** — `js.hcaptcha.com`, `api.hcaptcha.com` — [Terms](https://www.hcaptcha.com/terms)
   | [Privacy](https://www.hcaptcha.com/privacy)
 * **Google reCAPTCHA** — `www.google.com/recaptcha` — [Terms](https://policies.google.com/terms)
   | [Privacy](https://policies.google.com/privacy)

#### 3. Breached-password detection

**When:** Breached Passwords is enabled and somebody registers, resets a password,
or
 changes one on their profile.

Your site SHA-1 hashes the password and sends **the first five hexadecimal characters
of
 that hash and nothing else
 to Have I Been Pwned’s range API. The service answers
with the
 suffixes of every breached hash sharing that prefix, and the comparison
happens on your server. The password does not leave your site, and neither does 
its full hash — this is the k-anonymity model the service was designed around. No
account name, email address or IP address is sent. Responses are cached for 24 hours.
If the service is unreachable the check is skipped and the password is allowed, 
so an outage there never blocks a login here.

 * **Have I Been Pwned** — `api.pwnedpasswords.com` — [Terms](https://haveibeenpwned.com/API/v3#AcceptableUse)
   | [Privacy](https://haveibeenpwned.com/Privacy)

#### 4. Location & Network rules, when a database URL is configured

**When:** Location & Network is enabled _and_ you have pasted a database download
URL into
 its settings. There is no default URL and no built-in provider — with 
the field empty, nothing is ever downloaded.

A weekly scheduled task fetches the file from the address you gave it and stores
it under
 wp-content/uploads/. It is a plain download: no visitor data, no site 
data, and no IP address is sent, and it happens on a schedule rather than on a request.
Look-ups afterwards read the local file. If your host already reports a country —
Cloudflare’s `CF-IPCountry`, or a server-configured `GEOIP_COUNTRY_CODE` — that 
is used instead and no download is needed at all.

The address is whatever you configure. If you point it at MaxMind’s own endpoint
you are
 using their service under their terms with your own licence key:

 * **MaxMind GeoLite2** _(only if you configure it)_ — the host you supply — [Terms](https://www.maxmind.com/en/geolite2/eula)
   | [Privacy](https://www.maxmind.com/en/privacy-policy)

#### 5. Single sign-on (OpenID Connect)

**When:** you have added an OIDC provider of your own — Okta, Auth0, Keycloak, Entra
ID,
 Google Workspace, or anything else that publishes a discovery document — and
somebody uses it to sign in. There is no built-in provider and no default address.

Your site fetches the discovery document and the signing keys from the issuer URL
you
 configured, over HTTPS only, and caches both. Sign-in is the same OAuth exchange
as above, with the identity token’s signature verified against those keys on your
server. AuthDock reads the subject, name, email address, email-verified flag and—
if you have configured role mapping — the group claim. Nothing about your site or
its other users is sent.

 * **Your OIDC provider** _(only the issuer you configure)_ — their terms and privacy
   policy

#### 6. Text-message codes

**When:** SMS is enabled as a second factor _and_ you have connected a gateway yourself.

**No SMS provider ships with this plugin.** There is no account, no balance and 
no
 credentials of ours anywhere in it, and none of your messages pass through anything
of ours. Connecting Twilio, Vonage, MessageBird, AWS SNS or a corporate gateway 
is a filter — authdock_send_sms — and until something is hooked to it, no message
is sent and no outbound request is made. What is sent, and to whom, is entirely 
determined by the gateway you connect.

 * **Your SMS gateway** _(only the one you connect)_ — their terms and privacy policy

#### 7. Log streaming (webhooks)

**When:** Log Streaming is enabled _and_ you have entered a webhook URL. There is
no default
 endpoint.

Security events are POSTed as JSON to the HTTPS address you gave, **after the response
has
 already been returned to the visitor
, so an endpoint that is slow or gone 
never delays a
 sign-in. Each request carries the event type, the account ID, the
event’s context, your site’s URL and a timestamp, signed with an HMAC-SHA256 of 
the body using the secret you set. Which categories are sent is your choice. Plain
HTTP endpoints are refused. A failed delivery is retried four times over about an
hour and then given up on.

 * **Your webhook endpoint** _(only the one you configure)_ — their terms and privacy
   policy

#### 8. Scheduled log exports

**Never leaves your server.** A retention copy is written as JSON Lines into a directory

under `wp-content/uploads/` that is closed to the web server. If you give it an 
email address, it sends a note saying an export was written and how many entries
it holds — never the log itself, which would put your whole audit trail through 
a mail server. Listed here because it writes files, not because it contacts anybody.

#### 9. Passkeys

**Never.** WebAuthn is verified entirely on your own server — the CBOR parsing, 
the COSE key
 handling and the signature checks are all implemented in this plugin.
No attestation is sent anywhere and no third party is contacted. It is listed here
only to say so.

#### 10. Telegram notifications

**When:** you connect a Telegram bot on the Delivery Channels screen and choose 
Telegram as a
 delivery channel. Off until you do, and the plugin contacts Telegram
at no other time.

**Where:** `https://api.telegram.org` — Telegram Bot API, operated by Telegram Messenger
Inc.

**What is sent:** the text of the notification. That is the same content the email
version
 carries — for example the IP address that was locked out, the username 
an attempt used, and the time. Also your bot token, which is how the API authenticates
the request.

**When else:** while somebody is connecting their own Telegram account, the site
reads the
 bot’s pending messages so it can match the one-time token they were given.
That reads only messages sent to your own bot, and only during the minute or two
somebody is linking.

**Terms:** [Telegram Terms of Service](https://telegram.org/tos) ·
 [Telegram Privacy Policy](https://telegram.org/privacy)·
[Bot API Terms](https://telegram.org/tos/bot-developers)

**What is stored:** your bot token, encrypted; the chat ID alerts are sent to; and,
for each
 member who connects their own account, that member’s Telegram chat ID 
and handle. Member linking is off by default. All of it is removed when the plugin
is uninstalled, is included in a personal-data export, and is removed by a personal-
data erasure.

### Reporting a security issue

This plugin is the front door of the site it runs on, so security reports are welcome
and
 are handled ahead of feature work.

**Please do not report a vulnerability in the WordPress.org support forum or a public
issue
 tracker.
 Report it privately instead, by opening a security advisory at

https://github.com/FlyToRakib/AuthDock/security/advisories/new — which is private
by construction and can issue a CVE — or by asking for a private channel through
the contact form at https://degird.com/.

You can expect acknowledgement within three working days and an assessment within
seven.
 Disclosure is coordinated: a fix ships first and the advisory follows. Reporters
are credited by name in the release notes unless they ask not to be.

Findings that require a site administrator to act against their own site are out
of scope,
 as are the documented break-glass constants behaving as documented — 
they exist so a locked-out administrator can get back in, and they require access
to wp-config.php.

The full policy, including scope and supported versions, is in SECURITY.md in the
source
 repository.

### Privacy

**What AuthDock stores.** The audit log records authentication events — sign-ins,
failed
 attempts, lockouts, two-factor changes, password resets — each with the 
IP address and user agent of the request. Lockouts are stored against an IP address.
Two-factor secrets, backup codes, magic-link tokens and trusted-device records are
stored hashed or encrypted, never in plain text.

**How long.** The audit log is trimmed on a schedule you set on the Audit Log screen—

30 to 365 days, or unlimited. Lockout records expire on their own. Magic links expire
in minutes, and trusted devices on the duration you configure.

**How much.** The **What to Record** setting on the Audit Log screen chooses between

everything, security events only, and failures only, so a site that does not want
a record of every ordinary sign-in does not have to keep one.

**How much of an address.** The **Addresses** setting on the same screen chooses
between
 storing the whole address, the network only (`198.51.100.0`), a one-way
hash, and nothing at all. It defaults to the whole address, which is what the plugin
has always done. Lockouts and the allow and block lists are deliberately unaffected—
they have to compare a real address against a range, so anonymising them would switch
the protection off. They keep an address only for as long as the block lasts.

**On uninstall.** Deleting the plugin removes its settings, its tables and its user
meta by
 default. If you need the audit log to outlive the plugin — as a compliance
record often must — switch on **Keep my data when the plugin is deleted** on the
Audit Log screen before deleting.

**Data subject requests.** AuthDock is registered with WordPress’s own privacy tools.
Tools 
 Export Personal Data returns the account’s connected social accounts, known
addresses, remembered devices and last sign-in, plus every audit row belonging to
it. Tools  Erase Personal Data deletes those account records and strips the account,
address and browser from its audit rows, keeping the events themselves — an audit
trail a request can empty is not one. Two-factor secrets and backup codes are kept,
and the report says so: removing them would lock the account out of its own second
factor. Deleting the account removes them.

**Suggested policy text.** Settings  Privacy  _Check the policy suggestions_ includes
an
 AuthDock section describing what is collected and for how long, using the retention
period this site actually has configured.

**The full inventory** — every field, where it lives, why, its lifetime, and three
gaps named
 rather than left to be found — is in `docs/PRIVACY.md` in the plugin’s
repository.

### Bundled libraries

AuthDock ships one third-party library, unmodified and unminified:

 * **QRious 4.0.2** (`admin/js/vendor/qrious.js`) — [neocotic/qrious](https://github.com/neocotic/qrious),
   **
   GPL-3.0**. Draws the enrolment QR code in the browser, so a two-factor secret
   is never sent to a QR image service. It loads on the profile screen only, and
   only while enrolling.

It is the distribution its author published, copied by `bin/build-vendor.js` and
verified
 byte for byte by `npm run check:build` — there is no minification step
to reproduce, because the file that runs is the file that was released.

QRious is GPLv3 and AuthDock is GPLv2-or-later, which permits the combination; the
plugin as
 distributed is therefore effectively GPLv3. Both are GPL and both are
compatible with the WordPress.org guidelines.

## Screenshots

[⌊Dashboard — Overview of authentication activity with live stats and quick feature
toggles.⌉⌊Dashboard — Overview of authentication activity with live stats and quick
feature toggles.⌉[

**Dashboard** — Overview of authentication activity with live stats and quick feature
toggles.

[⌊Social Login Settings — Configure Google, Facebook, GitHub, and X OAuth providers
with button style options.⌉⌊Social Login Settings — Configure Google, Facebook, 
GitHub, and X OAuth providers with button style options.⌉[

**Social Login Settings** — Configure Google, Facebook, GitHub, and X OAuth providers
with button style options.

[⌊Magic Link Settings — Configure link expiry, rate limiting, allowed roles, and
force-magic mode.⌉⌊Magic Link Settings — Configure link expiry, rate limiting, allowed
roles, and force-magic mode.⌉[

**Magic Link Settings** — Configure link expiry, rate limiting, allowed roles, and
force-magic mode.

[⌊Two-Factor Authentication — TOTP and email-based 2FA setup with QR code provisioning
and backup codes.⌉⌊Two-Factor Authentication — TOTP and email-based 2FA setup with
QR code provisioning and backup codes.⌉[

**Two-Factor Authentication** — TOTP and email-based 2FA setup with QR code provisioning
and backup codes.

[⌊Login Protection — Brute force settings with progressive lockout, IP whitelist/
blacklist, and notification options.⌉⌊Login Protection — Brute force settings with
progressive lockout, IP whitelist/blacklist, and notification options.⌉[

**Login Protection** — Brute force settings with progressive lockout, IP whitelist/
blacklist, and notification options.

[⌊Dynamic Redirects — Role-based login and logout redirect rules with first-login
redirect.⌉⌊Dynamic Redirects — Role-based login and logout redirect rules with first-
login redirect.⌉[

**Dynamic Redirects** — Role-based login and logout redirect rules with first-login
redirect.

[⌊Audit Logs — Searchable, filterable log of all authentication events with CSV/
JSON export.⌉⌊Audit Logs — Searchable, filterable log of all authentication events
with CSV/JSON export.⌉[

**Audit Logs** — Searchable, filterable log of all authentication events with CSV/
JSON export.

## Blocks

This plugin provides 8 blocks.

 *   AuthDock Social Buttons The sign-in buttons for whichever providers you have
   switched on.
 *   AuthDock Account Dashboard Sessions, remembered devices, passkeys, connected
   accounts and recent security activity, on a page of your own.
 *   AuthDock Conditional Content Show what it contains only to signed-in visitors,
   signed-out visitors, particular roles, or people with a capability.
 *   AuthDock Login Form Display a complete login form with social login buttons,
   magic link, and 2FA support.
 *   AuthDock Log Out Button A log-out link that shows only to people who are signed
   in.
 *   AuthDock Lost Password Ask for a password reset link without leaving your own
   site.
 *   AuthDock Registration Form A registration form on a page of your own, so nobody
   has to be sent to wp-login.php.
 *   AuthDock Magic Link Sign in with a link sent by email, with no password at 
   all.

## Installation

 1. Upload the `authdock` folder to `/wp-content/plugins/`
 2. Activate the plugin through the ‘Plugins’ menu in WordPress
 3. Go to **AuthDock** in the admin menu to configure settings
 4. Enable the features you want to use

Or install directly from the WordPress plugin repository:

 1. Go to **Plugins  Add New** in your WordPress admin
 2. Search for “AuthDock”
 3. Click **Install Now**, then **Activate**

## FAQ

### What does AuthDock actually include?

These are the screens in the AuthDock menu. The setting-by-setting reference is 
in `docs/` in the plugin’s repository.

**🔑 Sign-in methods**

 * **Social login** — Google, Facebook, GitHub, X, Apple, Microsoft, LinkedIn, Discord,
   Twitch and Slack, with account linking, auto-registration, a default role and
   email-domain restriction.
 * **Magic links** — expiry, rate limiting, allowed roles, custom email copy. Single
   use, and dead the moment the password changes.
 * **Two-factor** — TOTP or emailed codes, per-role enforcement with a grace period,
   trusted devices, backup codes, encrypted secrets, replay protection.
 * **Passkeys** — first or second factor, verified on your own server, with clone
   detection.
 * **Single sign-on** — any OIDC provider with a discovery document, with role mapping.
 * **SMS codes** — through a gateway you connect via the `authdock_send_sms` filter.

**🛡️ Protection**

 * **Login limiter** — escalating lockouts, auto-blacklisting, CIDR and wildcard
   allow and deny lists, XML-RPC coverage, trusted proxies, admin alerts.
 * **Bot protection** — proof-of-work by default; Turnstile, hCaptcha and reCAPTCHA
   optional. A provider outage never becomes a login outage.
 * **Breached passwords** — checked by k-anonymity, so no password and no full hash
   leaves your site.
 * **Location & network rules** — allow or refuse by country or hosting network,
   per surface and per role.
 * **Hardening** — custom login URL, XML-RPC control, REST API restriction, user-
   enumeration blocking, a password policy, six security headers.

**👤 Users & access**

 * **Access control** — wp-admin restricted by role or IP, with an emergency bypass
   key.
 * **Sessions** — concurrent limits, idle timeouts, per-role cookie lifetimes, remote
   termination.
 * **Account centre** — every session, trusted device, passkey and connected account
   on one screen the user owns.

**📋 Monitoring**

 * **Audit log** — every authentication event in an indexed table; filter by type,
   date, user or address, export to CSV or JSON, expire on your own schedule.
 * **Notifications** — eight admin alerts and six user alerts, throttled, with a
   test send.
 * **Delivery channels** — the same alerts by email, by Telegram, or both, chosen
   separately for administrators and account holders. Members can connect their 
   own Telegram where a site allows it.
 * **Log streaming** — HMAC-signed JSON webhooks, sent after the response has gone
   out.
 * **Security score** — a weighted 0–100 rating, a seven-step setup walkthrough,
   an optional weekly digest.

**🧰 Recovery & appearance**

 * **Recovery** — `wp authdock` on the command line, `AUTHDOCK_SAFE_MODE`, a wp-
   config.php constant for every control that can lock you out, and Site Health 
   checks.
 * **Light, dark or system** — chosen per person, applied on the server, scoped 
   to AuthDock’s screens.

### Does AuthDock work with WooCommerce?

Yes. Social login buttons appear on WooCommerce login and checkout pages when WooCommerce
is active. Role-based redirects also work with WooCommerce customer roles.

### Is AuthDock multisite compatible?

Yes. Each subsite in a WordPress multisite network has independent settings and 
its own audit log table.

### Will AuthDock slow down my site?

No. AuthDock uses conditional asset loading — CSS and JavaScript load only where
needed. Database queries use proper indexing, and brute force tracking uses lightweight
transients instead of database writes.

### What happens when I deactivate the plugin?

Cron events are cleaned up, but your settings, database tables, and user data are
preserved so you can reactivate later without losing configuration.

### What happens when I delete the plugin?

All plugin data is completely removed: options, user meta (social IDs, 2FA secrets,
trusted devices), custom database tables, capabilities, and transients.

### Can I use social login and 2FA together?

Yes. When a user logs in via social login, they must still complete the 2FA challenge
if enabled for their account or role. AuthDock ensures 2FA cannot be bypassed regardless
of login method.

### What authenticator apps work with AuthDock 2FA?

Any TOTP-compatible app works, including Google Authenticator, Authy, Microsoft 
Authenticator, 1Password, Bitwarden, and FreeOTP.

### What if I get locked out by the custom login URL?

AuthDock includes a recovery key parameter. Access your login page via `?authdock_recover
=YOUR_KEY` to bypass the custom login URL block. The recovery key is set in your
security settings.

### Does brute force protection work with Cloudflare or reverse proxies?

Yes. Configure trusted proxy IPs in the login limiter settings, and AuthDock will
correctly read the real client IP from `X-Forwarded-For` headers.

### Can I export my audit logs?

Yes. Audit logs can be exported in CSV and JSON formats via the REST API or admin
UI. CSV exports include formula injection protection for safe spreadsheet use.

### Where can I put the login, registration and account forms?

Anywhere. Every form is a shortcode, a block and a theme-overridable template.

The shortcodes are `[authdock_login_form]`, `[authdock_register_form]`,
 [authdock_lost_password],`[
authdock_social_login]`, `[authdock_magic_login]`, [authdock_account] and `[authdock_logout_button]`.
There is a block for each of them, plus a Conditional Content block, and patterns
for a complete login page and a complete account page.

## Reviews

There are no reviews for this plugin.

## Contributors & Developers

“AuthDock — Login Security, 2FA, Social Login & Brute Force Protection” is open 
source software. The following people have contributed to this plugin.

Contributors

 *   [ RAKIBUZZAMAN ](https://profiles.wordpress.org/rakibantor/)

[Translate “AuthDock — Login Security, 2FA, Social Login & Brute Force Protection” into your language.](https://translate.wordpress.org/projects/wp-plugins/authdock)

### Interested in development?

[Browse the code](https://plugins.trac.wordpress.org/browser/authdock/), check out
the [SVN repository](https://plugins.svn.wordpress.org/authdock/), or subscribe 
to the [development log](https://plugins.trac.wordpress.org/log/authdock/) by [RSS](https://plugins.trac.wordpress.org/log/authdock/?limit=100&mode=stop_on_copy&format=rss).

## Changelog

#### 2.1.6

**The final pre-release audit.** A full security, correctness and stability review
of every module. Recommended for every site. Nothing is reset, no setting changes
meaning, and upgrading turns nothing on — but several controls that reported themselves
as protecting a site were not, and now do.

**Security controls that were not running**

 * **Location rules and bot protection did not stop a sign-in with a correct password.**
   Both refused before WordPress checks the password, and core’s authenticators 
   discard an earlier refusal when they are given a username and a password. A denied
   country, a filled honeypot and an unsolved challenge were each overwritten by
   a valid password. Both now run after core, where the login limiter has always
   sat. The “administrators only from these countries” rule could not fire at all.
 * **Suspending an account did not stop it signing in with its password** — the 
   same defect, one step earlier, so the check ran before there was an account to
   check.
 * **Location rules never applied on any site using a GeoLite2 database.** The database
   reader resolved pointers sixteen bytes early, so every lookup reported “no data”—
   and a rule with no data allows everyone, which made the failure silent and indistinguishable
   from the rule working.
 * **A country header was believed from any client**, so an allow-list of one country
   was open to anyone who put that country in a header. Forwarding headers are now
   honoured only from a configured proxy.
 * **Social sign-in, magic links and passkeys ignored the location rules, the address
   lockout and the risk engine**, because none of them goes through the password
   path those controls hook. All three now ask the same question.

**Account safety**

 * **A social sign-in could be finished by a browser that did not start it** — login
   CSRF, which signs a visitor into the attacker’s account. Each flow is now tied
   to the browser that began it.
 * **“Connect” on the profile page linked the wrong account, or registered a new
   one and signed the visitor into it**, logging them out of their own. It now links
   to the account that asked and signs nobody in.
 * **A new account could be registered on an address the provider had not verified**,
   which is the first half of an account takeover.
 * **The conditional-content block returned its gated content to anonymous REST 
   callers.**
 * **Frontend access control was bypassed by adding `?rest_route=` to any URL**,
   or by a percent-encoded spelling of a blocked path.
 * **The scheduled audit export was world-readable on nginx hosts**; its directory
   name is now unguessable.
 * **The webhook signing secret was stored, exported and shown in the clear.** The
   two-factor handoff record held the live challenge token in plain text.

**Settings that destroyed what they saved**

 * **Saving the Single Sign-On screen wiped the OIDC client secret**, and a newly
   typed one was stored unencrypted. Every write path now protects every section’s
   secrets.
 * **“Permanent block after: 0 to disable” was clamped to 1**, so switching auto-
   blacklisting off produced the strictest setting instead.
 * **A network policy or a `wp-config.php` setting could not actually switch a module
   on**, and importing a configuration could not shrink or clear a list.

**Features that did nothing**

 * **The concurrent-session limit never ended a session**, while logging that it
   had.
 * **The “new device” email to the account holder could never be sent.**
 * **The audit-log chain verifier reported tampering on any site with retention 
   enabled**, and the scheduled export re-sent the same oldest rows every run while
   claiming to attach a file it did not attach.
 * **The dormancy sweep only ever examined the first two hundred accounts**, and
   could suspend a network administrator.
 * **The risk engine’s impossible-travel signal was dead** unless another module
   happened to be switched on, and an enforced block wrote no log entry and sent
   no email.
 * **The conditional bot challenge never appeared** with the login limiter switched
   off.
 * **Apple and Twitch sign-in could not complete at all.** A custom magic-link email
   body was ignored, the register form’s redirect did nothing, and OIDC accounts
   could not be disconnected.

**Correctness and robustness**

 * **Password resets were broken on sites using the passwordless preset** — every
   reset link answered “invalid key”.
 * Attempt limits counted after checking rather than before, so concurrent requests
   shared one increment; spray detection blacklisted shared office and mobile addresses
   permanently; IPv6 wildcards only matched when zero-padded; dashboard rules ignored
   wildcards the screen accepted.
 * The generic login error replaced every message on every login-page form; the 
   audit-log screen and its exports could not load on plain permalinks; a large 
   JSON export exhausted memory; retention windows were off by the site’s UTC offset.
 * Two-factor codes could be submitted twice, the login form could be submitted 
   before the proof-of-work answer was ready, and the lost-password form said whether
   an address had an account.
 * Uninstalling left a stored phone number behind and, on multisite, ignored one
   site’s “keep my data” choice while honouring another’s.
 * On MySQL 5.6 and MariaDB before 10.2 the login-attempts table was never created;
   schema 8 shortens the index that prevented it.
 * New extension point: `authdock_passwordless_login_allowed`.

#### 2.1.5

**Two-factor after social sign-in and magic links now works without cookies.**

 * The challenge screen could only identify a sign-in by a cookie set on a previous
   response. Where something in front of the site strips cookies — a CDN or proxy
   in front of `/wp-json/` is the usual culprit, and social sign-in completes there—
   that cookie never arrived and the screen could only say the session was gone.
   The form now carries a single-use handle naming the challenge, and every path
   that completes a challenge accepts either. The cookie is still preferred; the
   password route is unchanged.
 * The handle is not the challenge token, which stays out of the markup for good.
   It expires with the challenge, survives a mistyped code, and stops working the
   moment the sign-in completes.
 * `POST /2fa/verify` was declaring `token` required, so it rejected the requests
   that correctly carry neither a token nor a handle.

#### 2.1.4

**Magic links and social sign-in, on sites with a persistent object cache.** Required
for every site running Redis or Memcached — which is most managed hosting.

 * **“Invalid or expired magic link” for a link minutes old.** The handle connecting
   a magic link to its account was stored as a transient, which on a host with a
   persistent object cache means it lived nowhere but that cache. Any flush — a 
   deploy, `wp cache flush`, a caching plugin’s Purge All — invalidated every link
   already sitting in an inbox. It is a database row now. Links sent before the 
   upgrade still work.
 * **The same fault in every OAuth flow.** The record of a social sign-in in progress,
   the OIDC nonce, and the name Apple sends only once were all transients too, so
   a flush mid-flow answered “This sign-in link has already been used or has expired”
   about a sign-in seconds old. All three moved to the database.
 * **2.1.3’s cache purge was itself flushing the object cache**, on any settings
   save. It is now page-caches only, and only for the settings that change which
   URLs must never be stored.
 * **“Session expired” after social sign-in.** The cookie carrying the two-factor
   challenge is set by one response and read after a redirect; anything in front
   of the site that strips cookies from `/wp-json/` responses broke that. The redirect
   now carries a single-use handle — not the challenge token — which the challenge
   screen exchanges for the cookie and then strips from the URL.
 * **A clearer error, and an audit trail.** A missing cookie, an expired challenge
   and a spent one no longer share one sentence, and both failures are recorded 
   in the audit log.

#### 2.1.3

**Sign-in bounced back to the login screen.** Two defects, found together on a live
site behind LiteSpeed Cache. Recommended for every site, and required for any site
running a page cache.

 * **The idle timeout ended every session at the moment it began.** The “last active”
   stamp was kept once per account and was never written at sign-in, so the first
   request after a fresh login read a timestamp from a session that had ended days
   earlier, decided the new session was idle, and logged it straight back out — 
   before it could record that anything had happened. Nothing could break the loop:
   every sign-in, by every method, returned to `wp-login.php?authdock_idle=1`. Activity
   is now tracked against the session making the request, so a session that has 
   just been created cannot be old, and one device’s activity no longer speaks for
   another’s. Upgrading clears the stale stamps.
 * **The login page could be cached.** A page cache that had stored `wp-login.php`
   served it from disk without running PHP — so no cookies were set, the two-factor
   challenge token was never issued, and a correct code was answered with “Session
   expired”; nonces in the stored copy aged out; and a visitor who did sign in went
   on seeing the logged-out site. AuthDock now declares every authentication URL
   uncacheable on the first request that reaches it, so no copy is stored at all,
   registers its cookies with the caches that vary on them, keeps its scripts out
   of defer/delay optimisation, and purges the login screens on activation and upgrade.
 * **Site Health checks for it.** A new diagnostic fetches the login page the way
   a visitor does and reports it if an edge cache is answering.
 * `AUTHDOCK_DISABLE_IDLE_TIMEOUT` joins the break-glass constants.

#### 2.1.0

**Notification channels, and a pre-release audit.** Alerts can now arrive by Telegram
as well as by email, and a final audit before public release closed five defects
that no automated test could have caught. Nothing is reset and no setting changes
meaning; upgrading turns nothing on.

**Notifications go somewhere other than email**

 * **Delivery channels.** Every alert used to end at `wp_mail()`. A handler now 
   describes what happened and a dispatcher hands a copy to each channel the site
   has chosen. Email behaves exactly as it did.
 * **Telegram, in about four steps.** Message `@BotFather`, paste the token, press
   Connect Bot; post in the chat you want alerts in, press Detect Chat. Then Send
   Test Message, which sends immediately so the answer on screen is what Telegram
   actually said.
 * **Chosen separately for administrators and for account holders** — both, either
   or neither. An upgraded site has no such setting stored, and an absent setting
   means email.
 * **Account holders can connect their own**, where a site allows it. Off by default:
   switching it on means storing a Telegram chat ID for each member who connects
   one.
 * **A third party adds a channel** with one subclass and one filter.

**Six providers that shipped and could not be reached**

 * **Apple, Microsoft, LinkedIn, Discord, Twitch and Slack can now be configured
   at all.** Their OAuth support arrived complete and correct, but four separate
   screens each carried a hand-written list of the original four providers — so 
   there was no field to enter a client ID for any of the six, their sign-in buttons
   rendered as blank unlabelled rectangles with a broken image, the profile screen
   showed no sign an account was linked, and a link to one of them could not be 
   removed. Every one of those screens is now built from the provider registry, 
   and the six missing brand marks have been drawn.
 * **Connected accounts appear where the plugin said they would.** The account centre’s
   connected-accounts list and the personal-data export both read a record that 
   nothing had ever written, so the section was hidden on every install and a subject
   access request under-reported. It is written now.

**Protection that was keyed on the CDN rather than the visitor**

 * **Trusted Proxies has a settings field**, on the Security screen where the documentation
   always said it was. It had no field anywhere, and the Site Health check that 
   told you to set it read a different option than the code that used it — so following
   the advice exactly changed nothing.
 * **It accepts CIDR ranges and wildcards.** It matched addresses exactly, which
   no site behind Cloudflare, Fastly or Akamai could ever satisfy, because they 
   publish ranges.
 * **The visitor’s address is read from the correct end of `X-Forwarded-For`.** 
   Every CDN appends the address it saw to whatever the client sent, so the left-
   most entry — which is what was read — is a value the visitor chooses. Anyone 
   behind a CDN could forge a fresh identity on every request and walk through lockouts,
   IP blocking and country rules. If you list a chain of your own proxies, name 
   all of them; a single proxy is unaffected.
 * **`CF-Connecting-IP` and `True-Client-IP` are read**, which Site Health had claimed
   since 1.1 and nothing did.
 * **The network-wide blocklist blocks.** On multisite, an address a super admin
   blocked across the network was blocked on no site at all.
 * **A broken mailer no longer reveals which addresses have accounts.** Every refusal
   on the magic-link form gave the same answer except a failed send, which only 
   an existing account could produce. The failure is now recorded in the audit log
   instead.

**Verification**

 * **The proof-of-work check is now proven, not assumed.** Bot protection defaults
   to proof-of-work, and the browser and the server carry independent SHA-256 implementations;
   if they ever disagreed by one bit, every visitor would be refused at the login
   form and no test would have noticed. The shipped solver is now run against the
   server’s verifier on every commit, and compared on tens of thousands of inputs.
 * **Passkeys are verified for every algorithm offered.** RS256 — what a TPM-backed
   Windows Hello credential commonly produces — and EdDSA had accepted-but-unexercised
   code paths. Both now register and sign in under test with real keys.
 * **Two-factor codes are checked against RFC 6238’s own published vectors**, so
   agreement with Google Authenticator, Authy and 1Password is anchored to the specification
   rather than assumed.

#### 2.0.0

**A major release.** The admin is rebuilt, and three security fixes ship with it.
Nothing about how people sign in changes and no setting is reset — upgrading moves
screens around, it does not turn anything on or off.

**The admin**

 * **Twenty-four menu entries become seven.** Related screens are grouped behind
   one entry with a rail down the side, and each panel keeps its own address — so
   the back button, a bookmark and a support link all still work. Old `page=authdock-*`
   links are redirected to wherever that screen lives now, with their query arguments
   intact.
 * **Setup is a stepper**, one step at a time, reachable from the dashboard rather
   than only on first install — and it can be dismissed and brought back.
 * **A light and a dark theme**, switched from the heading and remembered per person.
   Every colour on an AuthDock screen now comes from a token, so both themes stay
   consistent.
 * **The screens draw their own icons.** Dashicons is an icon font drawn for the
   2013 admin; all seventy-five icons are now inline stroke paths on the Lucide 
   grid (ISC licensed), shipped with the plugin rather than fetched from anywhere.
   Six screens that had been sharing an icon with something unrelated get their 
   own, and GitHub finally gets the GitHub logo.

**Security**

 * **Confirming your password is no longer something you can do all day.** Turning
   off two-factor, regenerating backup codes, disconnecting a social account and
   removing a passkey all ask for your password first — precisely so that a stolen
   session is not enough to undo them. None of them counted the wrong answers, and
   none goes through the login limiter, so whoever held a hijacked cookie could 
   guess at the password or the six-digit code as often as they liked. There is 
   now a shared allowance across all of those screens; once it is spent the route
   stops answering, and every failure is logged.
 * **A suspended account can no longer finish a two-factor challenge it had already
   started.** Suspension is checked when the password is submitted, which can be
   a quarter of an hour before the code is typed. Suspending somebody ended their
   sessions, and the challenge they had open handed them a new one.
 * **Saving every settings section at once no longer destroys your social login 
   secrets.** Reading the settings deliberately masks each OAuth client secret, 
   and this one route wrote the mask back over the real value — so a save could 
   silently break every configured provider. A new secret submitted there was also
   stored unencrypted, and a partial save erased the keys it did not mention. All
   three are fixed.

#### 1.3.0

**A large release.** 1.1, 1.2 and 1.3 were milestones in the development plan and
none of them shipped separately, so everything below arrives at once. Every new 
feature is off by default; upgrading changes nothing until you switch something 
on.

**Passkeys**

 * Sign in with a passkey, or use one as a second factor. Passkeys are the only 
   widely deployed factor that is phishing-resistant — the credential is bound to
   your site’s origin by the browser, so a proxy phishing kit that defeats app codes
   and SMS completely cannot relay one.
 * No new dependencies: the CBOR parsing, key decoding and signature verification
   are all done on your own server with what PHP already has. Nothing is sent to
   any third party.
 * Clone detection, credential-collision rejection, and a password required before
   adding or removing one.

**Your account, on your own site**

 * A new account screen — `[authdock_account]` or the Account Dashboard block — 
   showing where you are signed in, which devices skip the two-factor prompt, your
   passkeys, your connected accounts and your own recent security activity.
 * **End one session, not all of them.** WordPress offers “log out everywhere else”
   and nothing finer, so somebody who left a session open on a shared machine had
   to end every session they had.
 * Forget a remembered device, and the revocation is logged.

**A block for every form**

 * Registration and password recovery finally have a block, a shortcode and a theme-
   overridable template, so a site that hides wp-login.php has somewhere to put 
   them.
 * Seven new blocks in all — registration, lost password, magic link, social buttons,
   account dashboard, log-out button, and conditional content that shows or hides
   what it contains by sign-in state, role or capability — plus patterns for a complete
   login page and a complete account page.
 * jQuery is gone from the front end.

**Bot protection**

 * Automated submissions are refused on the login, registration, password-reset 
   and magic-link forms. Brute-force protection counts failures per address, which
   a distributed attack defeats by never repeating one; this raises the cost of 
   each attempt instead.
 * Three layers: a field no person can see, a floor on how fast a form can come 
   back, and — only after an address has already failed — a challenge, so an ordinary
   visitor never meets one.
 * The default challenge needs no third party and sends nothing anywhere. Cloudflare
   Turnstile, hCaptcha and reCAPTCHA are there for sites already using one.

**Location and network rules**

 * Allow or refuse sign-ins by country, on the login form, registration or the dashboard,
   with a tighter rule per role.
 * Refuse addresses on hosting networks, which stops a large share of automated 
   attacks with almost no effect on ordinary visitors.
 * Three guard rails against locking yourself out: your own address is exempted 
   when you save, a rule that would block your own location is refused with the 
   reason, and an address whose location is unknown is never blocked.

**Passwords, scoring and mail**

 * Known-breached passwords are refused, checked with k-anonymity — the password
   never leaves your site and neither does its hash.
 * A security score on the dashboard and a five-step hardening wizard, because the
   common failure is not misconfiguration: it is a site that installed a security
   plugin, switched nothing on, and believes it is protected.
 * An optional weekly digest: the score, what changed, and the three things most
   worth doing next.
 * Mail failures are no longer silent, and the plugin now tells you whether your
   domain publishes the SPF and DMARC records a receiving server checks — a message
   failing those is discarded with no bounce, which is how a magic link vanishes
   with nothing to see.

**Recovery**

 * `wp authdock` on the command line: `doctor`, `unblock`, `blocklist`, `recovery-
   link`, `2fa`, `sessions`, `logs export`, `settings export|import`, `upgrade` 
   and `bench`.
 * `AUTHDOCK_SAFE_MODE` and a constant for each control individually. Every control
   that can keep somebody out now has both a wp-config.php escape hatch and a CLI
   one.
 * Site Health integration: twelve checks covering tables, lockout storage, secrets,
   outbound mail, sender authentication, cron and proxies.

**Fixed**

 * Two-factor codes could be brute-forced, the attempt limit resetting on every 
   login. It applies to the account now.
 * The lockout screen and dashboard counters showed nothing on any site with a persistent
   object cache, while lockouts were actively blocking logins.
 * Social login buttons and magic-link forms were invisible on WooCommerce and any
   other front-end login page — two headline features dark on a large share of installs.
 * Application passwords, XML-RPC and REST authentication worked again with two-
   factor enabled; they had been receiving a chunk of the login page instead of 
   a real response.
 * Backup-code verification went from roughly a second of CPU to under a millisecond.
 * Roughly eight database queries removed from every page load on a site with features
   switched off.
 * Privacy: a personal-data exporter and eraser, an IP-anonymisation setting, and
   a documented record of every field stored.
 * Accessibility: inline handlers and inline styles removed throughout, live regions
   that screen readers actually announce, and a notice that no longer removes itself
   after five seconds.
 * Full details of all 75 findings, including the ones deliberately not fixed and
   why, are in the plugin’s `docs/fix-and-improve` directory.

#### 1.0.3

**Security release — everyone should update.**

 * Fixed: social login could take over an existing account. An OAuth identity was
   matched by email address alone, without checking whether the provider had verified
   it. A provider-verified address is now required, and accounts with elevated capabilities
   are never linked automatically — they must be connected from the profile screen.
 * Fixed: OAuth login CSRF. The `state` parameter was identical for every logged-
   out visitor and was never consumed, so a captured callback could sign a victim
   into an attacker’s account. Each sign-in now gets its own single-use value.
 * Fixed: “Restrict REST API to authenticated users” was bypassable by adding the
   plugin namespace to any query string. Matching is now done on the resolved route.
 * Fixed: two-factor codes could be brute-forced, because the attempt limit reset
   every time the login form was re-submitted. The limit now applies to the account.
 * Fixed: an IP-list entry with a missing range prefix, such as `10.0.0.0/`, silently
   matched half the internet. Such entries are now rejected and named in an admin
   notice.
 * Fixed: PKCE is now sent to every OAuth provider, not only X.
 * Fixed: the two-factor challenge token no longer travels in the URL, where it 
   leaked into browser history, Referer headers, and access logs.
 * Fixed: a mistyped code during two-factor re-enrolment destroyed the working secret.
 * Fixed: failed and successful two-factor attempts are now recorded in the audit
   log.
 * Fixed: a blocked IP could grow the audit log without bound.
 * Fixed: with two-factor enabled, application passwords now work. REST and XML-
   RPC authentication previously received a chunk of the login page instead of a
   real response, breaking the WordPress mobile apps, Jetpack, backup tools, and
   headless front-ends.
 * Fixed: `AUTHDOCK_VERSION` was left at 1.0.0 through earlier releases, so browsers
   never re-fetched updated CSS or JavaScript.
 * Note: users whose social provider reports an unverified email, and users with
   elevated roles, will need to log in with a password once and connect their social
   account from their profile.

#### 1.0.2

 * Documentation only. No plugin code changed.

#### 1.0.0

 * Initial release
 * Social Login with Google, Facebook, GitHub, and X (Twitter) via OAuth 2.0
 * Magic Link passwordless login with configurable expiry, rate limiting, and force-
   magic mode
 * Two-Factor Authentication — TOTP (RFC 6238) and email-based 2FA with encrypted
   secret storage, backup codes, trusted devices, and per-role enforcement
 * Brute force protection with configurable attempts, progressive lockout escalation,
   IP whitelist/blacklist with CIDR and wildcard support, and auto-blacklist
 * Dynamic login/logout redirects with per-role configuration and first-login redirect
 * Comprehensive audit logging to custom database table with retention, filters,
   CSV/JSON export, and auto-cleanup
 * Security hardening — custom login URL with recovery key, XML-RPC control, REST
   API restriction, user enumeration prevention, password strength enforcement, 
   and 6 security HTTP headers
 * wp-admin access control with role-based and IP-based restrictions, admin bar 
   hiding, emergency bypass key, and smart AJAX/cron exceptions
 * Session management — concurrent session limiting, idle timeout, per-role session
   duration, admin session viewer, and remote termination
 * Email notification system with 8 admin triggers, 6 user self-notification triggers,
   configurable throttling, custom recipients, and test email
 * REST API namespace `authdock/v1` with 15+ endpoints for all data operations
 * 5 custom capabilities for granular permission control
 * Full i18n support with `.pot` file
 * WordPress.org compliance — GPL-2.0+, no tracking, no encoded code, third-party
   service disclosure

## Meta

 *  Version **2.1.6**
 *  Last updated **2 lá ago**
 *  Active installations **Fewer than 10**
 *  WordPress version ** 6.0 or higher **
 *  Tested up to **7.1**
 *  PHP version ** 7.4 or higher **
 *  Language
 * [English (US)](https://wordpress.org/plugins/authdock/)
 * Tags
 * [access-control](https://ga.wordpress.org/plugins/tags/access-control/)[brute force protection](https://ga.wordpress.org/plugins/tags/brute-force-protection/)
   [login security](https://ga.wordpress.org/plugins/tags/login-security/)[social login](https://ga.wordpress.org/plugins/tags/social-login/)
   [two factor authentication](https://ga.wordpress.org/plugins/tags/two-factor-authentication/)
 *  [Advanced View](https://ga.wordpress.org/plugins/authdock/advanced/)

## Ratings

No reviews have been submitted yet.

[Your review](https://wordpress.org/support/plugin/authdock/reviews/#new-post)

[See all reviews](https://wordpress.org/support/plugin/authdock/reviews/)

## Contributors

 *   [ RAKIBUZZAMAN ](https://profiles.wordpress.org/rakibantor/)

## Support

Got something to say? Need help?

 [View support forum](https://wordpress.org/support/plugin/authdock/)

## Donate

Would you like to support the advancement of this plugin?

 [ Donate to this plugin ](https://degird.com)