Skip to content

Approve the AWS sign-in without showing a window - #85

Merged
popen2 merged 1 commit into
mainfrom
claude/frost-auto-approve-aws-o8yleo
Aug 31, 2026
Merged

Approve the AWS sign-in without showing a window#85
popen2 merged 1 commit into
mainfrom
claude/frost-auto-approve-aws-o8yleo

Conversation

@popen2

@popen2 popen2 commented Aug 21, 2026

Copy link
Copy Markdown
Owner

Closes #1. Rebased onto main at c378f9b (picks up #82, #84, #86, #87, #88).

AWS SSO's device authorization is a multi-step approval — confirm the request, sign in, grant access — and none of the approval steps ask for anything the user has to supply. Frost now clicks them itself: the login page loads in a window that stays off screen, and a refresh covered by a live identity provider session finishes with nothing appearing at all — no window, no browser tab, no Dock icon.

When the window does come up

The moment the page needs the user, and never later than that:

  • an empty visible field to type into — password, username, one-time code. The device page's own code field arrives prefilled from verificationUriComplete, which is exactly the distinction that makes this work;
  • a WebAuthn wait, or the security-key account picker, through a new onUserNeeded callback on attachLoginIndicator(). The picker is a modal sheet, so it has to ask for the window before it opens — a sheet on a window nobody can see is a prompt nobody can answer;
  • anything off the expected path: a page it cannot read, a button AWS has renamed, a load that fails, or no navigation/click for 12s (60s absolute).

In default browser mode that same moment hands over to shell.openExternal and drops the silent probe — that user picked the browser because that is where their passkeys and saved passwords live. The probe is destroyed only once the browser is actually up; destroying it first and then failing to open anything would leave the run polling with nothing on screen.

Clicking is deliberately narrow

The buttons next to the ones we want deny the request, so guessing wrong is worse than stalling — and stalling shows the window, which is the safe failure. The driver only clicks:

  • on the device-authorization hosts (*.awsapps.com, device.sso.<region>.amazonaws.com), never on the identity provider's pages;
  • controls matched by AWS's own ids (cli_verification_btn, cli_login_button) or by an exact label ("Confirm and continue", "Allow access");
  • never one whose label reads like a refusal, whatever its id says;
  • at most a few per document.

Scanning continues after the user takes over, so the approval steps that follow their sign-in are still clicked for them.

Changes

  • src/approve-overlay.ts — the driver, browser-world code alongside the existing overlay and under the same tsconfig.overlay.json compile.
  • src/auto-approve.ts — the main-process half: injects the driver, reads its console signals, and owns the stall/total timers that guarantee the login is always eventually handed to the user.
  • src/page-script.ts — the script loading and sub-frame injection both injected scripts need. For the WebAuthn overlay this is the dom-ready fallback for frames the document-start hook cannot reach (Show the credential overlay when the page asks for the key as it loads #87), lifted out of login-indicator.ts unchanged; the approval driver only ever needed that half.
  • attachLoginIndicator() takes an optional onUserNeeded callback.
  • Behavior → Approve automatically turns it off; on by default. README, AGENTS.md and the docs site are updated.

How it sits with the recent login work

Verification

npm run build and npm run lint (oxlint) pass.

npm run check:overlay passes#87's regression test, run here under xvfb. It exercises the injection path this PR refactored, and reports the wait for both the early (document-start) and late (dom-ready, now via page-script.ts) cases.

For the driver itself, the built dist/approve-overlay.js is run through new Function("window", source) against a stub window, once per page shape: confirm page (clicks confirm, ignores cancel, does not mistake the prefilled code for a prompt), allow page, sign-in page (no clicks off an AWS host, asks for the user), an empty OTP field, the approved page, a cli_login_button relabelled "Cancel request" (not clicked), an unrecognised button (left alone, says nothing), disabled and hidden controls, and click-once. 16 checks, all passing; the harness is described in AGENTS.md.

Still needs a desktop smoke test against the real AWS pages — the id and label matching, and how a hidden window behaves through a real federated redirect, are the parts that cannot be proven headlessly. A real-Electron check:auto-approve in the style of check:overlay would be the way to close that gap, and is a natural follow-up.

@popen2 popen2 added the feature label Aug 21, 2026 — with Claude
AWS SSO's device authorization is a multi-step approval — confirm the
request, sign in, grant access — and none of the approval steps ask for
anything the user has to supply. Frost now clicks them itself: the login
page loads in a window that stays off screen, and a refresh covered by a
live identity provider session finishes without a window, a browser tab
or a Dock icon appearing at all.

The window comes up the moment the page needs the user — a password or a
one-time code to type, a security key to touch, a passkey to pick — and
on anything off the expected path: a page Frost cannot read, a load that
fails, a flow that stops making progress. In default-browser mode that
same moment opens the browser instead, which is where that user's
passkeys and saved passwords live, and the hidden probe is destroyed once
the browser is actually up.

Clicking is deliberately narrow, because the buttons next to the ones we
want deny the request: only on the device-authorization hosts, only
controls matched by AWS's own ids or by an exact label, never one whose
label reads like a refusal, and only a few per document. Anything
unrecognised stalls, and stalling shows the window.

- src/approve-overlay.ts drives the page, alongside the existing overlay
  and under the same compile; src/auto-approve.ts watches it and owns the
  timers that guarantee the login is always eventually handed over.
- src/page-script.ts holds the loading and sub-frame injection both
  injected scripts need — the overlay's dom-ready fallback for frames the
  document-start hook cannot reach, and the approval driver.
- attachLoginIndicator() takes an onUserNeeded callback: a WebAuthn wait,
  and especially the modal account picker, must not happen behind a
  window nobody can see.
- Behavior → Approve automatically turns it off, on by default.

Closes #1

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018XK1mi3rSPLzxu7XUhyC6a
@popen2
popen2 force-pushed the claude/frost-auto-approve-aws-o8yleo branch from eec4abf to 20f9274 Compare August 31, 2026 06:17
@popen2
popen2 enabled auto-merge August 31, 2026 06:22
@popen2
popen2 merged commit 61c5634 into main Aug 31, 2026
9 checks passed
@popen2
popen2 deleted the claude/frost-auto-approve-aws-o8yleo branch August 31, 2026 06:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Automatically approve OAuth request

2 participants