Skip to main content

Playwright-based browser authentication bridge for HTTP APIs with complex auth flows

Project description

web-auth-bridge

CI PyPI Python License: MIT

A Python library for authenticating against HTTP APIs whose login flows require a real browser — SSO, SAML, Cloudflare, or stateful web portals — and then reusing the resulting session for fast programmatic access.

Overview

web-auth-bridge separates authentication from execution:

  1. A Playwright-driven browser performs the login once.
  2. The resulting cookies and tokens are extracted into a typed AuthResult and cached on disk.
  3. Subsequent calls use a plain httpx client with those cookies, or, when a site requires a browser beyond login, a pool of pre-authenticated headless contexts.

The library is intended for CLIs, agents, and integrations that need to script against sites with complex or interactive authentication.

Installation

pip install web-auth-bridge
playwright install chromium

For sites that reject Python's default TLS fingerprint (for example, Garmin's OAuth2 token exchange):

pip install "web-auth-bridge[tls-impersonation]"

Quick start

import asyncio
from web_auth_bridge import WebAuthBridge, AuthResult, Credentials

class ExampleCallback:
    async def authenticate(self, page, credentials):
        await page.goto("https://example.com/login")
        await page.fill('input[name="email"]', credentials.username)
        await page.fill('input[name="password"]', credentials.password)
        async with page.expect_navigation():
            await page.click('button[type="submit"]')
        return AuthResult()

    async def is_authenticated(self, result):
        return not result.is_expired

async def main():
    bridge = WebAuthBridge(
        app_name="example",
        auth_callback=ExampleCallback(),
        credentials=Credentials(username="me@example.com", password="..."),
    )
    await bridge.ensure_authenticated()

    async with bridge.http_client() as client:
        resp = await client.get("https://example.com/api/me")
        print(resp.json())

asyncio.run(main())

On the first run the browser opens to log in. On subsequent runs the cached session is reused until it expires.

When to use it

  • Sites guarded by Cloudflare or other WAFs that challenge non-browser clients.
  • SAML or OAuth portals without a public token endpoint.
  • Internal applications requiring MFA or interactive SSO.
  • Stateful web portals (for example, ASP.NET) with no HTTP API surface.
  • CLI tools for personal or private APIs where reimplementing the auth flow would cost more than the tool itself.

If a site already offers a clean API token, use httpx directly.

Alternatives

A managed browser is not always the right tool. Lighter-weight approaches exist and, when they work, cost a fraction of the memory and startup time:

  • cloudscraper, curl_cffi, and tls-client impersonate real browser TLS and HTTP/2 fingerprints to defeat fingerprint-based WAFs without running a browser.
  • hrequests and botasaurus wrap similar techniques with higher-level scraping APIs.
  • Hand-crafted HTTP flows against documented OAuth, OIDC, or token endpoints remain the best option whenever a site exposes them.

web-auth-bridge exists for the cases those approaches do not cover: interactive SSO, MFA, SAML, stateful web portals, JavaScript-rendered challenges, and WAF rulesets that evolve faster than any fingerprint library can track. The tradeoff is resource cost for resilience — running an actual browser is heavier than a spoofed request, but it behaves like a browser because it is one, and it continues to work when the underlying site changes.

Modes

Mode Credentials source Browser visible Typical use case
Headless + stored creds .env / config file No Fully automated CLIs and agents
Headed + stored creds .env / config file Yes Debugging; sites requiring a visible UI
Headed + manual entry User types into page Yes Secrets that must not be stored on disk
Headless + no creds Cached session No Every run after the first, while cached

Parallel headless browsers

For sites without a usable API, the bridge can produce a pool of pre-authenticated browser contexts:

await bridge.ensure_authenticated()

async with bridge.context_pool(size=4) as pool:
    pages = [await ctx.new_page() for ctx in pool]
    ...

Documentation

  • Architecture — components, flows, and diagrams
  • Design notes — decisions, alternatives, and constraints
  • Examples — minimal snippets for common flows
  • Testing — unit, integration, and live-site tests
  • Garmin example — end-to-end Cloudflare-guarded SSO plus OAuth2 Bearer token flow

Development

git clone https://github.com/mikejhill/web-auth-bridge
cd web-auth-bridge
uv sync --all-extras
uv run playwright install chromium
uv run poe test
uv run poe cov
uv run poe lint

Contributions are welcome. Please use Conventional Commits; the release workflow derives versions from commit messages.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

web_auth_bridge-0.1.1.tar.gz (25.7 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

web_auth_bridge-0.1.1-py3-none-any.whl (26.1 kB view details)

Uploaded Python 3

File details

Details for the file web_auth_bridge-0.1.1.tar.gz.

File metadata

  • Download URL: web_auth_bridge-0.1.1.tar.gz
  • Upload date:
  • Size: 25.7 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for web_auth_bridge-0.1.1.tar.gz
Algorithm Hash digest
SHA256 bc6be36f25ffeb858cd0ca50bf0b4f32701779c9c94db92b097e32811885f9ee
MD5 41b9b2a3b182b6994e1dfd0b6caf4de9
BLAKE2b-256 04b3036f0fc4a8212c63ad02d348caaf7c0c2bdd4d5b13f87abf08c1ac2b2748

See more details on using hashes here.

Provenance

The following attestation bundles were made for web_auth_bridge-0.1.1.tar.gz:

Publisher: release.yml on mikejhill/web-auth-bridge

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file web_auth_bridge-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: web_auth_bridge-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 26.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for web_auth_bridge-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 de6f9cdfb0ab64c3f88dbb17cced913840ba4d5c90e5690ca2887426028ce02f
MD5 356f0950f59abf029e70537155a0475c
BLAKE2b-256 8e1767f36fdadbeed30b02b0707058bc9c46cdfbce91087a1f5da0eecaea63ca

See more details on using hashes here.

Provenance

The following attestation bundles were made for web_auth_bridge-0.1.1-py3-none-any.whl:

Publisher: release.yml on mikejhill/web-auth-bridge

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page