duo-pass
Duo second-factor handling for Playwright logins — push approval with Verified
Push number matching, or a typed passcode — behind one Approver interface.
Spun out of canvasser, where it was
proved against a live Duo tenant. GPL-3.0-or-later.
This module never asks how the Duo page was reached and never leaves the Duo host except by Duo handing control back. The login flow that got here is the host application's business.
from playwright.sync_api import sync_playwright
from duo_pass import complete_duo, PushApprover, configure
configure(
snapshot=lambda page, label: save_somewhere(page, label),
announce=lambda number: show_somehow(number),
)
with sync_playwright() as p:
... # reach the Duo challenge on `page`
complete_duo(page, PushApprover()) # or PasscodeApprover()
Hooks
A library must not invent paths or terminal chrome, so three seams connect this module to its host. All have working defaults; all should be overridden by any host with its own state directory, display layer, or code source.
| seam | signature | default |
|---|---|---|
snapshot |
(page, label) -> Path |
PNG under ./snapshots/, mode 700/600 |
announce |
(number: str | None) -> None |
framed box on stderr |
code_source |
() -> str |
prompt on the controlling terminal |
snapshot fires as duo-exit-error (Duo refused the session) and
duo-timeout (still on Duo when the wait expired). announce fires with
Duo's Verified Push number, or None when the tenant has Verified Push off —
absence is normal, not an error, and the frame is drawn either way.
code_source is taken by PasscodeApprover(code_source=...) and supplies the
6-digit code; the default prompts on /dev/tty — never stdin, so a pipe or a
redirect cannot silently feed it — and refuses with guidance where no terminal
exists. A host with a secrets file, a vault, a web UI, or no terminal supplies
its own instead of subclassing.
Notes
- The wait watches for leaving the Duo host, never for Duo markup — markup changes, leaving does not.
- The trust prompt ("remember this device") is clicked during the wait, not after it: waiting to leave Duo before handling the prompt deadlocks, because the missing click is what would let us leave.
- The Verified Push number is re-read every few seconds while waiting. A push can expire and be re-sent with a different number, and a stale number on screen is worse than none.
- A Duo
error=exit is reported as Duo refusing the browser, not as the user failing to approve. A timeout says what it knows: approval may have worked while Duo never handed control back. - Nothing here retries a credential. Repeatedly submitting a bad passcode can
lock the account; a wrong code raises
ApprovalErrorinstead.
Release files for duo-pass 0.0.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| duo_pass-0.0.2.tar.gz | 21.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| duo_pass-0.0.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 43.7 kB
Release files / duo_pass-0.0.2.tar.gz
| Download URL | duo_pass-0.0.2.tar.gz |
|---|---|
| Size | 21.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9a7772f338f16d8588b05413d892316b9def6b784a91d146b2e3959647cc1215
|
|
BLAKE2b-256 checksum How to use checksums |
83f98c71500cf609bce4b023a6005e4b2f9beac0fdc2a6b804a880fd7e397e42
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.5
|
Release files / duo_pass-0.0.2-py3-none-any.whl
| Download URL | duo_pass-0.0.2-py3-none-any.whl |
|---|---|
| Size | 22.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
d4762613ea874f0ea55c66dab65d9b2426ab1af6c120b8e56f2fb2dd148e3faf
|
|
BLAKE2b-256 checksum How to use checksums |
1009bce19ee454d14510dfd710e3893185cb864459efe8efa0a8a9b2030d4642
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.5
|