This episode covers the security aspects of browser automation: automating secure login flows, handling 2FA, SSO, and OAuth, testing accessibility and secure content, and capturing console logs and network errors from the browser.

The tests that break most often — and carry the most risk — are those dealing with login and security. Real applications have multi-factor authentication, SSO, OAuth, and pages only certain users can access. Episode 12 covers how to automate those flows without sacrificing security.
The core challenge of automating secure flows is the conflict: you need credentials and sessions to test, but credentials must never leak into the repository or logs. This episode provides secret management patterns, strategies for handling 2FA and SSO, and how to capture security evidence from the console and network.
Never write credentials inside your code. Store them in environment variables and read them at runtime:
import os
email = os.environ["TEST_EMAIL"]
password = os.environ["TEST_PASSWORD"]
halaman = LoginPage(driver)
halaman.isi_email(email)
halaman.isi_password(password)
halaman.klik_masuk()os.environ["TEST_EMAIL"] reads the value from the environment. Locally, the value goes in .env (never committed); in CI, it enters as a secret in the pipeline settings.
Security tests also validate that pages are properly protected:
driver.get("https://app.example.com/dashboard")
assert "login" in driver.current_urlassert "login" in driver.current_url proves that anonymous users are redirected to the login page. This is a simple yet important assertion: route protection should always be tested, not assumed.
One-time codes (TOTP) can't be predicted, so don't try to type real codes repeatedly. The common approach is to bypass 2FA in tests using an already-authenticated session:
cookies = [
{"name": "session", "value": os.environ["TEST_SESSION"], "domain": "app.example.com"},
]
driver.get("https://app.example.com/login")
for c in cookies:
driver.add_cookie(c)
driver.get("https://app.example.com/dashboard")driver.add_cookie(c) injects the session cookie obtained from a 2FA process done once outside the test. This way, tests don't need to guess TOTP codes — but the session must be refreshed before it expires.
For SSO based on an external provider, separate two responsibilities: test the SSO flow once to make sure the callback works, and skip SSO in other functional tests by using a direct session. Automating an external provider in every test makes the suite slow and dependent on systems outside your control.
Pages displaying sensitive data — like card numbers or identities — must be tested to ensure the data doesn't leak onto the wrong surface:
kartu = driver.find_element("id", "ringkasan-kartu")
assert kartu.get_attribute("data-masked") == "true"
assert "4111" not in kartu.textget_attribute("data-masked") validates that the application marks the data as masked, and the second assertion ensures the full number doesn't appear. Tests like this prevent security regressions in UI areas that are easy to overlook.
Selenium can capture logs from the browser. Enabling logging requires special options in Chrome:
from selenium.webdriver.chrome.options import Options
opsi = Options()
opsi.set_capability("goog:loggingPrefs", {"browser": "ALL", "performance": "ALL"})
driver = webdriver.Chrome(options=opsi)goog:loggingPrefs with the value {"browser": "ALL", "performance": "ALL"} enables two kinds of logs: browser console and network performance logs. After the test finishes, fetch and inspect them:
for entry in driver.get_log("browser"):
if entry["level"] == "SEVERE":
print("Error konsol:", entry["message"])driver.get_log("browser") returns the list of console logs. Filtering for the SEVERE level catches JavaScript errors invisible to tests, such as bugs that only appear in certain browsers.
Performance logs contain request and response data. You can look for failed requests by filtering on specific URLs — this helps ensure no resources fail to load while the test runs.
Warning
Never print cookie contents or tokens to test logs. CI logs are often shared across teams; a session leak through logs is a real security incident.
Episode 12 balances two demands: smooth automation and preserved security. You now manage credentials through the environment, bypass 2FA and SSO with injected sessions, test masked sensitive content, and capture console and network errors as evidence of quality.
Key takeaways:
In episode 13 next, we'll cover test stability and flakiness — minimizing flaky tests with reliable selectors, retry strategies and flaky test detection, monitoring execution stability, and best practices for a stable automation suite.