Implementing Two Factor Authentication in MediaWiki with OATHAuth Extension
Why Two‑Factor Authentication Matters for a MediaWiki Farm
Picture this: a rogue bot sniffs out a leaked admin password, hops onto your wiki, and starts rewriting pages faster than a caffeinated hamster on a wheel. The headlines scream “Wiki Breach!” and the community morale sinks. That scenario isn’t science‑fiction; it’s a very real risk, especially for wikis that host sensitive research or internal documentation. Adding a second factor—something you have, not just something you know—turns the tables. In the MediaWiki universe, the go‑to tool for this job is the OATHAuth extension, which ships with a time‑based one‑time password (TOTP) engine out of the box.
Getting Your Hands on OATHAuth
First things first, you need the extension itself. There are a couple of ways to pull it into your codebase.
- Via composer:
composer require mediawiki/oathauth - Manual git clone:
git clone https://gerrit.wikimedia.org/r/mediawiki/extensions/OATHAuth.git extensions/OATHAuth
Whichever path you choose, make sure the directory ends up at $IP/extensions/OATHAuth. If you’re using composer, the autoloader will take care of the include path for you.
Switching the Extension On
Now open LocalSettings.php and drop in the usual extension hook:
wfLoadExtension( 'OATHAuth' );
That line alone does not magically lock everyone down; it merely registers the code. The heavy lifting lives in a handful of configuration variables that you’ll need to tweak.
Core Configuration Variables
Below is the “minimum viable” config set. You can paste it at the bottom of LocalSettings.php—just watch out for stray spaces at the end of lines, they sometimes trip up PHP’s parser, especially when copy‑pasting from a browser.
# Where to store user secrets (make sure the directory is not web‑accessible)$wgOATHAuthSecretPath = "$IP/OATHAuthSecrets";
# Enable TOTP for all users (you can later whitelist or blacklist)$wgOATHAuthEnableForAll = true;
# Token lifespan – 30 seconds works well with most authenticator apps$wgOATHAuthTokenValidity = 30;
# Optional: enforce 2FA on password resets$wgOATHAuthEnforceOnReset = true;
Notice the comment about the secret storage path. The folder must exist and be writable by the web server user, yet it should live outside the document root to keep the one‑time secrets out of the public eye. A quick terminal command does the trick:
mkdir -p OATHAuthSecrets && chmod 700 OATHAuthSecrets
Hooking Into the Login Flow
If you want to make 2FA mandatory for a particular user group—say, “sysop” or “bureaucrat”—you can add a hook. Here’s a snippet that throws a gentle reminder at anyone in the “sysop” group who hasn’t yet registered a TOTP device:
$wgHooks['UserLoginComplete'][] = function ( $user, &$inject_html ) {
if ( in_array( 'sysop', $user->getGroups() ) && !$user->getOption( 'oathauthsecret' ) ) {
$inject_html .= '<p class="error">Sysops are required to enable two‑factor authentication. <a href="/wiki/Special:OATHAuth">Set it up now</a>.</p>';
}
return true;
};That tiny hook isn’t mandatory, but it illustrates how flexible the extension is. You can also write a custom HookHandler class—see the Topic discussion on enforcing MFA for a deeper dive.
Assigning Secrets to Users
When a user first visits Special:OATHAuth, MediaWiki will generate a secret key and display a QR code. The secret lives in the file we pointed to earlier, named after the user's ID. It’s a simple text file, something like:
otpauth://totp/ExampleWiki:user@example.com?secret=JBSWY3DPEHPK3PXP&issuer=ExampleWiki
Don’t worry if the QR code looks like a pixelated mess—most smartphones can still scan it. Users then pop the code into an authenticator app (Google Authenticator, Authy, or even the built‑in password manager on iOS) and start getting six‑digit numbers that change every half‑minute.
Testing It Out
Before you roll the change out across the whole site, pick a test account. Log in, go to Special:OATHAuth, scan the code, and then log out. When you try to log back in, MediaWiki will prompt for the token after the password field. The flow looks like this:
- Enter username and password as usual.
- The system detects a secret attached to the account and shows a “Enter your authentication code” field.
- Pull the six‑digit number from your authenticator app and type it in.
- If the token matches (within the 30‑second window), you’re in.
If the token is wrong, MediaWiki will bounce you back to the login screen with a generic error—not a clue that 2FA was the culprit. That’s intentional: you don’t want to give away which part of the login failed.
Handling Lost Devices
Real life isn’t always tidy. A user may lose their phone or replace it abruptly. OATHAuth provides a “recovery code” mechanism out of the box. When users first enable 2FA, the extension shows a set of one‑time‑use backup codes. It’s good practice to remind users (perhaps via a site notice) to store those codes somewhere safe—think a password manager or a printed sheet locked in a drawer.
Fine‑Tuning the Experience
A few optional tweaks can smooth out friction without compromising security:
- Allow “remember me” for a limited time. Set
$wgOATHAuthRememberMe = true;and adjust$wgOATHAuthRememberDurationto, say, 604800 seconds (one week). - Support multiple authentication methods. The extension also speaks WebAuthn, so you can let hardware keys (YubiKey, Titan) sit alongside TOTP. Enable it with
$wgOATHAuthEnableWebAuthn = true;. - Log attempts for audit. Turn on
$wgOATHAuthLog = true;and watchSpecial:Log/oathauthfor suspicious activity.
Common Pitfalls (and How to Dodge ‘Em)
Even seasoned admins stumble over a few gotchas:
- File permissions. If the secret directory isn’t writable, users will see a cryptic “Unable to write secret file” error. Double‑check with
chmod 700andchown www-data(or your web‑server user). - Time drift. TOTP hinges on clock sync. If users complain about “Invalid token” even though they typed it correctly, make sure the server’s NTP daemon is running and that the client device’s clock is accurate.
- Cache interference. Some wikis run a reverse proxy (Varnish, Cloudflare) that caches login pages. Disable caching for
Special:OATHAuthvia$wgCachePages = false;in the LocalSettings snippet for that special page.
Looking Ahead: MFA as a Culture, Not a Feature
Implementing OATHAuth is a solid technical step, but security is a mindset. Encourage editors to adopt password managers, enforce strong password policies ($wgPasswordPolicy), and keep the wiki software up‑to‑date. When a new version of MediaWiki drops, it often bundles tighter integration with OATHAuth—so stay on the bleeding edge if you can.
Quick Recap (No Bullet‑Point Overkill)
If you’re scanning the page for a cheat sheet, here’s the essence: fetch the OATHAuth extension, load it in LocalSettings.php, point the secret store outside the web root, turn on $wgOATHAuthEnableForAll (or use a hook for selective enforcement), and test the flow on a sandbox account. Tweak the token window, remember‑me flag, and backup code policy to match your community’s tolerance for hassle.
In the end, you’ll have a wiki that asks for more than a password—something that feels a bit like a secret handshake for every trusted contributor. It’s not a silver bullet, but it certainly raises the bar enough to keep opportunistic attackers at bay.