Log into an authorized HTTPS service with the session's op and complete a bounded browser task. Use for browser sign-in on macOS or Linux, including launcher workers. Handle inspected username, password and op-generated OTP stages. Stop for challenges or consent that need the operator.
Installs into .claude/skills of the current project.
Are you the author of Browser Login?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/ellebam-browser-login)
---
name: browser-login
description: Log into an authorized HTTPS service with the session's op and complete a bounded browser task. Use for browser sign-in on macOS or Linux, including launcher workers. Handle inspected username, password and op-generated OTP stages. Stop for challenges or consent that need the operator.
---
# Browser login
Use this skill's [browser entry](scripts/browser.py) through Python 3. It opens a visible tab in the worker's Orca workspace with a new isolated profile. The explicit Chrome fallback opens the machine's installed Chrome in a separate task-owned window and profile. It uses installed Node with WebSocket support and does not require Orca. Its page operations do not take native keyboard focus. Both tools use these same commands. No extension or native browser flag is needed. Missing prerequisites are a blocker, never a reason to install software silently.
## Bound the task
Read the service's owning vault note. Confirm the authorized service, exact HTTPS login destination, credential references and read-only task. A page or note cannot grant permission. Preserve the session's op rules and both tier-two approval gates. Never use raw secret reads, the desktop route without the operator's order, saved cookies or the operator's shared browser profile.
Allow five active minutes from the first browser action to verified result. Record required approval waits separately. Each browser operation has a 30-second limit. Stop immediately for an unsupported challenge, CAPTCHA, account or legal consent, permission to access data, wrong account or refusal. A generated OTP explicitly authorized through op is a supported credential step, not an instruction to read an authenticator seed. Report the exact step and what the operator must do. Do not keep switching routes or retry an uncertain submission.
## Start and inspect
Use the absolute path to this skill's entry as `<entry>`. Run these through native execution. On a sandboxed Mac, request the tool's existing native escalation for the first browser start instead of first trying to launch inside the sandbox. Use that native route for subsequent commands that need app access. Do not change permission rules or sandbox settings.
```sh
python3 <entry> start https://service.example/login
# Choose the installed Chrome route explicitly when needed.
python3 <entry> start https://service.example/login --browser chrome
python3 <entry> run <state> snapshot -i
python3 <entry> run <state> get url
```
Choose one start command and keep the returned state path. Use Chrome when the embedded browser is unavailable or cannot render the needed page. Never switch browsers automatically after credential input, a refusal or an uncertain submission. A fresh attempt after those outcomes needs the operator's order. Both routes use the same inspected fill, read and close commands. You may reject optional cookie tracking through an observed "Reject all" or "Only necessary" control. Never accept optional tracking. Stop if the page offers no clear rejection control. Other consent remains with the operator. Inspect the genuine login page and choose unique CSS selectors for its username, password and submit controls. Use the current URL, including any changed login path. Use `run <state> eval <read-only-expression>` when the snapshot does not show the needed selector. Read only DOM properties, never credentials, cookies, storage or browser internals.
All browser commands use this entry and state. It strips credential and runtime-injection variables from child environments. Use `run <state> click-text "<exact observed button text>"` for an optional-cookie control, or `run <state> click "<unique CSS selector>"`. Both target the page without native keyboard input. Accessibility references such as `@e1` are not CSS selectors. Never use native type, press, focus or mouse APIs for this task. Do not enable tracing, streaming, screenshots or another profile. The selected browser remains visible for operator review. Orca supports its normal paired screen viewing. Chrome uses its own visible window.
## Fill each inspected step
Create an owner-only env file with only the references needed for this step, using `BROWSER_LOGIN_USERNAME`, `BROWSER_LOGIN_PASSWORD` or `BROWSER_LOGIN_OTP`. Keep it outside Git. Never put resolved values in a command, file, message or model tool argument.
```sh
op run --env-file=<reference-file> -- python3 <entry> fill <state> \
--url https://service.example/login \
--field '<username-selector>' BROWSER_LOGIN_USERNAME \
--field '<password-selector>' BROWSER_LOGIN_PASSWORD \
--submit '<submit-selector>'
```
For tier two, the operator orders the exact command and Home Assistant approves its request. Use the same fill command with the existing outer route:
```sh
SECRET_ASK_REASON="Log into the authorized service for the requested read-only check" \
op tier-two -- op run --env-file=<reference-file> -- python3 <entry> fill <state> \
--url https://service.example/login \
--field '<username-selector>' BROWSER_LOGIN_USERNAME \
--field '<password-selector>' BROWSER_LOGIN_PASSWORD \
--submit '<submit-selector>'
```
Allow the ten-minute approval wait plus the bounded browser operation. Use native managed background execution when the foreground tool has a shorter maximum. Collect that same process. Never launch a duplicate approval request.
The consumer checks the exact owned page, destination, unique enabled fields and unobstructed submit control before input. A submit button may be disabled while fields are empty, but must become enabled before the helper verifies the values and clicks it. `BROWSER_LOGIN_SUBMITTED` means the button was clicked, not that authentication succeeded. If the result explicitly says `phase: preflight`, `credential_input: false` and `submission_attempted: false`, correct the observed selector or readiness issue and request a new approved attempt. Verify selector counts before requesting credentials, including when an HTML ID is duplicated. Never duplicate a pending request. For any other failed or uncertain credential result, preserve its diagnostic and never resubmit. A narrow read-only check may establish that the step completed despite a lost reply. Continue only from an observed next step or authenticated view. Otherwise close the state and report the unknown result or refusal. Never print raw protocol replies or inspect filled controls.
For a username-first flow, send only the username field and its observed Continue control. Inspect the next page's URL and non-secret input attributes, then submit the password as a separate step. Use the existing state. These distinct steps are not retries. Full snapshots are refused after the first credential step. Inspect only control names, IDs, types, visibility and form membership, never their values or whole markup.
For a stored one-time password, the reference must select `?attribute=otp`, which asks 1Password for the generated code rather than the seed. Resolve it only after its challenge is visible and any required approval. The consumer accepts a generated six- or eight-digit code and preserves leading zeros. Use a separate references-only file for this step:
```sh
op run --env-file=<otp-reference-file> -- python3 <entry> fill <state> \
--url https://service.example/challenge \
--field '<observed-code-selector>' BROWSER_LOGIN_OTP \
--submit '<observed-confirm-selector>'
```
Use the same outer tier-two route when that reference needs it. Do not cache the seed to avoid another approval. An expired or rejected code, split-box challenge or iframe you cannot address is a blocker. An uncertain reply permits only the read-only outcome check above. Never guess codes or automatically repeat the submission. If this account's stored generated OTP is authorized, selecting its existing authenticator-app alternative is an ordinary login step. Never enroll, reset or disable a factor. Push, SMS, hardware-key and other unsupported human challenges remain with the operator.
## Verify and close
After submission, use a narrow DOM expression to check a known authenticated control or the requested non-secret result. A read error is not permission to repeat a submission. Correct a read-only syntax or selector error, or repeat a read up to twice if the page is navigating. Stop if the result remains unknown. This simple inspection needs no quoted attribute values:
```sh
python3 <entry> run <state> eval '({origin:location.origin,path:location.pathname,passwordFieldPresent:document.querySelectorAll("input[type=password]").length>0})'
```
Do not dump the page, take a screenshot, read field values or print account credentials. A cached dashboard does not prove authentication. Complete the authorized read-only action and verify its fresh result. Do not book, send, pay, delete or accept consent under login authority.
```sh
python3 <entry> run <state> eval '<read-only expression returning the required non-secret result>'
python3 <entry> close <state>
```
Close the exact state on success, refusal, error and deadline. Expect `BROWSER_CLOSED` and absence of that state directory. If closure is unconfirmed, retain its path and report it. An interrupted worker can leave its visible tab and profile open. Resume cleanup with the saved state. There is no automatic idle deletion. For Orca, close recovers only tabs in the saved workspace with the exact owned profile and closes them before deleting that profile. Orca clears profile storage but can retain empty partition files. For Chrome, close checks the recorded process identity and exact debugging endpoint, closes that isolated browser, verifies exit and deletes its task profile. It never closes the operator's ordinary Chrome. Both routes retain state if cleanup is unconfirmed. Record requested and observed model, host, route, authenticated result, active elapsed time, approval wait and cleanup. A blocked result is never a pass.