Key takeaways
- What you never store cannot be stolen from you, so prefer keeping the secret out entirely.
- Session handoff also solves multi-factor naturally, because the person is present.
- Injected secrets leak through error handling far more often than through storage.
- MFA is a wall, and designing for the pause is more honest than routing codes.
- A logged-out agent sees a login page rather than an error, and will fill fields into it.
Three approaches, in order of preference
Authentication is where most browser automation becomes insecure, usually by taking the simplest path: store the password, type it in. There are better options and they are not much harder.
The ordering is by how much you hold. What you never store cannot be stolen from you, so prefer approaches that keep the secret out of your system entirely.
There is a fourth option worth checking first: whether authentication is needed at all. Many application flows work without an account, and a design that only authenticates where the portal actually requires it removes the problem for most of the traffic.
- Session handoff — the user signs in; you receive only a session, never a password
- Secret injection — a password in a vault, injected at use, never in the model’s context
- Stored credentials — last resort, encrypted per user, with explicit consent
| Approach | You store | Cost |
|---|---|---|
| No authentication | Nothing | Only works where portals allow it |
| Session handoff | A session, expiring | Periodic re-authentication |
| Secret injection | A vault-held password | Leak paths through logs and errors |
| Stored credentials in the app | A password | Hard to justify |
| Credentials in the model context | Everything, everywhere | Never do this |
Session handoff is usually possible
The user signs in themselves — in a browser you control, or in an extension running in theirs — and what your system keeps is a session cookie rather than a credential. The password never exists in your infrastructure.
This also handles multi-factor authentication naturally, because the human is present exactly when the second factor is required. Sessions expire, which is a genuine cost, but the security difference is large enough to justify a periodic re-authentication prompt.
Treat the session with the care a credential deserves, because for the duration of its life that is what it is. Encrypted at rest, scoped to one user, never in a log or a trace, and deleted when the user disconnects the account.
Isolate the browser context per candidate without exception. A reused profile carrying one person’s session into another’s run is a straightforward data breach, and it is easy to introduce by accident while optimising away browser startup time.
If you must inject a secret
Keep it in a proper secrets manager, fetch it at the moment of use, type it into the page, and discard it. It should never appear in a prompt, a tool argument the model can see, a log line, or an error report.
The practical failure here is error handling: a login that fails and logs the attempted values, or a monitoring service that captures the request body. Audit those paths specifically, because they leak far more often than the intended storage does.
Screenshots are the browser-specific version of the same leak. A failure capture taken on a login page may contain a password field that was not masked, and an automatic screenshot-on-error policy quietly writes credentials into an artefact store nobody scoped.
Make revocation something the user can reach in one action. They should be able to disconnect an account without contacting support, and that same path is what you will use during an incident to invalidate everything at once.
Multi-factor is a wall, and that is fine
An agent cannot complete a second factor that requires a device or a human. Attempts to route one-time codes through the automation are a bad idea: you end up storing or forwarding the factor that exists precisely to require a person.
Design for the pause instead. When MFA appears, the agent should stop, notify the user, and resume once a session exists. Treating this as a supported state rather than an error makes the whole system more honest and considerably easier to operate.
Make the pause cheap to recover from. A saved run state, a clear notification naming the site, and a resume that picks up at the exact step it stopped turns the interruption into a minute of the candidate’s time rather than a lost application.
Expect it more often than the first sign-in. Portals challenge on a new device, a new location or after a period of inactivity, so MFA is a recurring state in normal operation rather than a one-time setup step.
Detect expiry properly
A logged-out agent rarely sees an error. It sees a login page, and if it is not looking for one it will happily interpret it as the page it wanted and start filling fields into it.
Check for an authenticated marker before every consequential action — an element that only appears when signed in. If it is missing, stop and re-authenticate rather than proceeding. Without this check, session expiry presents as mysterious silent failures rather than as the simple cause it is.
Detect by symptom rather than by a timer. A redirect to sign-in, a step that resets, or a form rejecting everything are all expiry, and a countdown based on an assumed session lifetime will be wrong for most of the portals you meet.
Never let the agent type credentials into a page it did not expect. A login form appearing mid-flow is a stop condition, because the one scenario where it is not an expired session is the one where something has redirected the agent somewhere it should not be.
Frequently asked questions
What is the safest way to authenticate a browser agent?
Session handoff — the user signs in themselves and your system receives only a session, never a password. It also handles MFA naturally, because the person is present when the second factor is needed.
Can an AI agent handle multi-factor authentication?
It should not try. Routing one-time codes through automation means storing or forwarding the very factor designed to require a human. Pause, notify the user, and resume once a session exists.
Where do injected credentials usually leak?
Error handling and failure screenshots. A failed login that logs attempted values, or an automatic capture of an unmasked password field, leak more often than the intended store.
How does an agent know its session expired?
By checking for an authenticated marker before every consequential action, and detecting by symptom rather than a timer. A logged-out agent sees a login page rather than an error.
Should an agent ever type credentials into an unexpected login form?
No. A login page appearing mid-flow is a stop condition, because the alternative explanation is that something redirected the agent somewhere it should not be.
Is a stored session as sensitive as a password?
For the duration of its life, yes. Encrypt it, scope it to one user, keep it out of logs and traces, and delete it when the account is disconnected.
Check this against your own resume
Scan your CV against a real job description, or build a parse-safe one from scratch. Your first scan costs nothing.
