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

Browser-assisted authentication for HTTP APIs that fight back.

Many interesting APIs can't be reached with plain HTTP: they hide behind SSO, SAML, Cloudflare challenges, or stateful web portals with no JSON surface. web-auth-bridge uses Playwright to handle the login once, extracts the resulting cookies and tokens as plain data, and hands them to your consumer code so every subsequent call is a fast httpx request.

What it does

  • Logs in with a real browser (Playwright / Chromium) so WAFs, JS challenges, and SAML redirects all just work.
  • Extracts cookies and tokens into a typed AuthResult — no more hairy JSON digging.
  • Caches auth on disk at ~/.config/<app>/auth_cache.json so every run after the first is cache-warm.
  • Issues parallel authenticated browsers when a site has no clean HTTP API (classic ASP.NET portals, etc.).
  • Runs headless or headed, with credentials from a file or typed by the user into a visible browser.

Install

pip install web-auth-bridge
playwright install chromium

For sites that reject Python's default TLS fingerprint (e.g. Garmin's DI OAuth2 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()  # cookies auto-extracted from the context

    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())

The first run opens Chromium; the second (within cookie lifetime) doesn't.

When to use it

Use web-auth-bridge when you need to script against a site whose auth flow you can't or don't want to reimplement by hand:

  • Cloudflare / other WAFs that challenge non-browser clients.
  • SAML/OAuth portals where the app doesn't expose a token endpoint.
  • Company intranets that require MFA or interactive SSO.
  • Scraping portals with stateful sessions and no API.
  • CLI tools for personal/private APIs where reimplementing the auth dance is more work than the tool is worth.

Don't use it when you already have a clean API token — plain httpx is fine there.

Modes

Mode Credentials from Browser visible? Typical use case
Headless + stored creds .env / file No Fully automated CLIs and agents
Headed + stored creds .env / file Yes Debugging; sites that require a visible window
Headed + manual entry User types into page Yes Sensitive credentials never written to disk
Headless + no creds Previously-cached No Every post-first run

Parallel headless browsers

await bridge.ensure_authenticated()

async with bridge.context_pool(size=4) as pool:
    pages = [await ctx.new_page() for ctx in pool]
    # All four pages start already authenticated.
    ...

Useful for portals where every read is a full page render.

Docs

  • Architecture — components, flows, and diagrams
  • Design notes — decisions, alternatives, constraints
  • Examples — minimal snippets for common flows
  • Testing — how to run unit, integration, and live-site tests
  • Garmin example — end-to-end Cloudflare-guarded SSO + 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     # unit + integration
uv run poe cov      # with coverage report
uv run poe lint     # ruff check

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

License

MIT © Mike Hill

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.0.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.0-py3-none-any.whl (25.7 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: web_auth_bridge-0.1.0.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.0.tar.gz
Algorithm Hash digest
SHA256 1d8da3014d1381cbc6c6893c3b14571c90e9843f78c13980cafe7278cd60110e
MD5 98b49b84a5e29ad4422342484e886cfd
BLAKE2b-256 05bba1e2066bb3681ea8aefb319114a42fe4f8d9627bd693d7cfc2d34ebf19f2

See more details on using hashes here.

Provenance

The following attestation bundles were made for web_auth_bridge-0.1.0.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.0-py3-none-any.whl.

File metadata

  • Download URL: web_auth_bridge-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 25.7 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.0-py3-none-any.whl
Algorithm Hash digest
SHA256 04b53df12ba6b391309757ca314726344160e649f8d35aea77830aa928c9f748
MD5 fc14ddb1f331058f37526598f41e2647
BLAKE2b-256 e99ad6ffe94f153b9271c522d47a73e4e80eecb39645d76086877ec1ea3e3aa1

See more details on using hashes here.

Provenance

The following attestation bundles were made for web_auth_bridge-0.1.0-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