Maintaining WordPress sites behind HTTP Basic auth — Playwright, urllib, and encrypted credentials A developer built a utility module to handle HTTP Basic auth credentials for WordPress maintenance tools using Playwright and urllib. The module centralizes credential extraction and encryption, preventing format mismatches and silent failures in rollback decisions. It uses Fernet encryption for passwords at rest and ensures existing sites without auth keys continue to work unchanged. It's pretty common to throw a layer of HTTP Basic auth on a WordPress site: a staging environment before launch, an internal test instance only employees should see, or any environment that wants an extra gate before the WordPress login screen itself. From a maintenance-tool point of view, this setup creates a peculiar "half-working, half-broken" asymmetry. The SSH/WP-CLI side runs fine. But everything HTTP-based — visual checks, thumbnail generation, browser-based fallback updates — hits 401 and dies. This post walks through how we resolved that asymmetry. A maintenance tool actually touches a Basic-auth-protected site through two distinct paths: browser.new context → navigation → screenshotWith no credentials, both paths see a 401 Unauthorized from the protected site. The Playwright symptom is the obvious one: the screenshot you save is the browser's "authentication required" dialog. The thumbnail grid fills with dark auth-prompt images, and you start wondering whether anything actually works. The urllib symptom is much worse — it silently breaks rollback decisions . A 401 baseline followed by another 401 after the update looks like "nothing changed = healthy." Real failures can hide behind that match, and the rollback that should have fired never does. When the same credentials need to flow through multiple code paths, picking them out of the site dict separately at each call site invites format-mismatch and missed-update bugs. So the first thing we did was build a small core/basic auth utils.py module that owns every form of credential extraction . python core/basic auth utils.py def get basic auth tuple site : """Return user, password , or None if not configured.""" if not isinstance site, dict : return None user = site.get 'basic auth user' or '' .strip pw = site.get 'basic auth password' or '' if not user: return None No user → treat as "no auth" return user, pw def get playwright http credentials site : """Returns dict for Playwright's new context http credentials=... .""" auth = get basic auth tuple site if auth is None: return None return {'username': auth 0 , 'password': auth 1 } def get basic auth header site : """Returns {'Authorization': 'Basic