Kernel

this week

AI ArticlesKernel Team

Agent Identity: How to authenticate an AI browser agent

A guide to authenticating AI agents on the open web — why prompts, cookie snapshots, and shared vaults fail, and how Kernel's Managed Auth fixes each of them.

TL;DR

  • Credential storage should remain outside the agent context, so the LLM can request access without reading or transmitting secrets.
  • An isolated login state machine should handle passwords, 2FA, SSO, and one-time codes outside the agent's reasoning loop.
  • A reusable browser profile should retain authenticated state, which prevents repeated logins during later tasks.
  • Session controls should detect expired authentication on a schedule and re-authenticate through the same protected flow. Removing access is an explicit act: drop the credential, the connection, and the profile.
  • Kernel's Managed Auth provides one worked implementation of this general agent auth pattern.

Why logged-in access breaks most agent architectures

Useful browser agents often need access to protected accounts. An invoice agent may read a procurement portal, while a healthcare agent may update an EHR system. Analytics dashboards and e-commerce accounts impose the same requirement. A browser-agent design usually takes one of two risky paths to authenticate.

The first path gives the model login credentials or a session token. Prompt injection can then steer the agent into submitting those secrets somewhere unintended. Credentials may also appear in prompts, tool arguments, traces, or application logs, which expands the number of places an attacker can extract them. Ending the agent run does not remove that authority because the credentials remain valid until someone rotates or revokes them.

The second path keeps credentials outside the model but builds custom login logic for every site. Each integration must handle consent screens, SSO redirects, and multifactor challenges such as one-time codes. Sites regularly change page structure and authentication rules, so previously working flows require ongoing repairs. Supporting ten domains can produce ten separate implementations with different failure states and recovery paths.

Both paths couple authentication too closely to agent execution. The agent should receive an authenticated browser state with limited scope and a clear lifetime, rather than the secrets or site-specific steps used to create it.

One boundary is worth naming early, because the rest of this pattern depends on it. Keeping the credential away from the model removes one class of exposure, but it does not remove the agent's authority. An agent driving an authenticated browser can still read data or take actions as the account holder, whether it was instructed to or injected into doing so. Credential isolation limits what leaks; it does not by itself limit what the agent can do. Scope, monitoring, and an explicit teardown path handle the second problem.

The correct pattern: five principles for agent authentication

A safe agent authentication architecture gives the browser authenticated state without giving the model the secret that created it. Five principles preserve that boundary throughout the session.

  1. Keep credentials outside the agent loop. A dedicated credential service should collect, encrypt, and store passwords or access keys. The agent should receive a reference to an authenticated profile rather than the underlying secret. Prompt injection, model logs, tool output, and browser observations cannot expose credentials that never enter the model context.
  2. Run login as a separate state machine. The authentication service should track explicit states such as pending user action, awaiting verification, authenticated, and failed. It should resolve SSO redirects, one-time passwords, and two-factor challenges through a protected interface outside the agent's reasoning loop. Site-specific changes then affect the authentication component instead of forcing the agent to improvise through an unfamiliar login screen.
  3. Persist authenticated state in a reusable profile. After login succeeds, the authentication service should save the resulting cookies and other browser state in a profile that the agent can reference later. Reusing that profile avoids repeated logins, which consume execution time and can trigger security checks or bot detection. Treat the profile as the unit of isolation: everything stored in one profile shares a cookie jar, so separate agent identities belong in separate profiles.
  4. Check session health on a schedule. A successful login can later fail because a cookie expires, a site invalidates a session, or an administrator changes an account policy. A background check should periodically load the profile and confirm it is still logged in, then attempt re-authentication through the same protected flow when it is not. Automatic recovery only works for flows that can be replayed without a human, so the design should also surface a clear "needs a person" state.
  5. Make sessions ephemeral and removal explicit. Browser sessions should be short-lived and disposable, so an agent that crashes or times out leaves nothing running behind it. The durable artifact is the profile, and durability is the point — that is what lets the next run skip the login. Because it is durable, removing access has to be a deliberate act across every layer that holds it: the stored credential, the authentication connection, and the profile itself. Sessions already established at the site remain valid until the site expires them or the user revokes them in account settings, so a full offboarding path has to account for that too.

Together, these principles separate long-lived secrets, authenticated browser state, and short-lived agent access. Each layer can then apply its own storage, monitoring, and teardown rules without trusting the LLM to enforce them.

Implementing the pattern with Kernel's Managed Auth

Kernel Managed Auth implements these principles through a connection, a login session, and a browser profile. The connection stores authorization for one domain without placing credentials inside the agent loop. Kernel encrypts credentials at rest with per-organization keys, never returns them through API responses, never writes them to logs, and never passes them to an LLM.

First, create a Managed Auth Connection and attach it to the profile that will represent the agent. If the profile does not exist, Kernel creates it. Each connection targets one domain. To constrain where credentials may be entered as the flow moves across redirects, set allowed_domains — when that field is omitted or empty, credential entry is not restricted to the primary domain. Common SSO provider domains such as Google, Microsoft, Okta, Auth0, and GitHub are allowed automatically and do not need to be listed.

Next, start a login session for the connection and follow its state until it reports SUCCESS. You can send the user to the Kernel-hosted login page, embed the @onkernel/managed-auth-react component in your own application, or drive the flow programmatically by handling discovered fields, sign-in options, and MFA selection yourself. Kernel resolves 2FA, SSO, and one-time passwords inside the isolated login flow, so the agent never reasons over those secrets. Passkeys and hardware security keys are the current exception — a site that requires one fails the flow with unsupported_auth_method, though an account that supports password plus TOTP is fully automatable.

Finally, launch a browser with the same profile. The browser loads the authenticated session state and opens the target site already logged in.

import Kernel from "@onkernel/sdk";


const kernel = new Kernel({ apiKey: process.env.KERNEL_API_KEY! });


const profileName = "procurement-agent";


// 1. Attach one authenticated domain to a persistent profile.
const connection = await kernel.auth.connections.create({
  domain: "vendor.example.com",
  profile_name: profileName,
});


// 2. Start the login flow. Hand hosted_url to the user, or pass
//    handoff_code to <KernelManagedAuth /> to render it in your own app.
const login = await kernel.auth.connections.login(connection.id);


// The SSE stream ends on its own at a terminal state:
// SUCCESS, FAILED, EXPIRED, or CANCELED.
const events = await kernel.auth.connections.follow(connection.id);


let finalState;
for await (const event of events) {
  if (event.event === "managed_auth_state") {
    finalState = event;
  }
}


if (finalState?.flow_status !== "SUCCESS") {
  throw new Error(`Login ended with status ${finalState?.flow_status}`);
}


// 3. Launch a browser that loads the authenticated profile.
const browser = await kernel.browsers.create({
  profile: { name: profileName },
  stealth: true,
});


console.log(browser.session_id);

Login, follow, and submit are all methods on kernel.auth.connections, keyed by the connection ID. The login response's id field is that same connection ID rather than a separate login identifier.

Your application should treat the login session as a state machine rather than assuming that submitting credentials completes authentication. The stream carries the flow through redirects, consent screens, and additional verification, and terminates on its own once the flow resolves. A failed or expired flow returns a controlled state — with an error code such as credentials_invalid, bot_detected, captcha_blocked, or unsupported_auth_method — without exposing the underlying credentials.

Kernel persists the successful authentication in the named profile, which avoids repeated logins on later browser launches. Managed Auth owns tab state on the profiles it maintains, so pass start_url when your automation needs to begin on a specific page.

How session health checks actually run

Once a connection is AUTHENTICATED, Kernel runs health checks on a configurable interval. Each check launches its own short-lived browser with the profile and verifies the session is still valid. These checks are scheduled against the connection — they do not observe your agent's live browser or its traffic.

When a check finds the session expired, Kernel replays the saved login flow in the background and writes the refreshed state back to the profile. That path requires two conditions, exposed together as can_reauth:

  1. A credential is linked — saved automatically during a successful login (the default), pre-stored through kernel.credentials.create(), or sourced from a connected 1Password vault.
  2. No external action is required — the saved flow needs no SMS or email OTP, push approval, or manual MFA selection. One-time codes are never stored. Adding a totp_secret to the credential converts an authenticator-app step into a replayable one.

If either condition fails, the connection moves to NEEDS_AUTH and waits for a fresh login session. Automatic re-authentication is triggered only by a failed scheduled health check, so it has no effect when health_checks is disabled.

Because re-authentication refreshes the profile rather than a live browser, a browser that is already running will not pick up the new session. Check the connection's status before launching, or call .login() to force authentication immediately — it returns quickly when the profile is already valid.

The check interval defaults to 3600 seconds and can be raised to 86400. The minimum depends on your plan: 5 minutes on Enterprise, 20 minutes on Start-Up, 1 hour on Hobbyist, 6 hours on Free. These are ordinary browser sessions, typically 5 to 30 seconds each, and they count toward browser usage and concurrency like any other session.

Ending sessions and removing access

Deleting a browser destroys that browser and its CDP endpoint, so that session cannot make further requests. Browsers are ephemeral by default: a session with no CDP client, live view viewer, or computer-controls request in flight enters standby and is deleted after its timeout. An agent process that crashes or hangs therefore does not leave a browser running indefinitely.

The authenticated state itself is deliberately durable. It lives in the profile so later launches skip the login, which is the property that makes the whole pattern efficient. Removing that access is a separate, explicit act:

  • Delete the credential to stop automatic re-authentication. Deleting a credential unlinks it from every connection that referenced it.
  • Delete the connection to end its health-check and re-auth loop and cancel any in-progress login. This does not clear cookies already saved to the profile.
  • Delete the profile to remove the stored browser state itself.

Sessions the site has already issued stay valid until the site expires them or the user revokes them in account settings. Kernel does not revoke them on your behalf, so treat that as a separate step in any offboarding or compromise-response path.

Running one agent identity across multiple tools

A single Kernel browser profile can hold multiple Managed Auth connections, each targeting one domain. You can attach a CRM connection and a procurement portal connection to the same profile, then launch one browser where the agent is authenticated to both tools at once.

The profile serves as the agent's persistent identity container. When the agent opens either site, the browser presents that site's cookies under normal browser origin rules while the LLM receives only page content and available actions. Because everything in a profile shares one cookie jar, the profile — not the individual connection — is the boundary to reason about: give distinct agent identities distinct profiles.

Profiles load read-only unless you pass save_changes: true, and only one writer is safe at a time, since each save replaces the profile's stored state wholesale.

Adding another tool repeats the connection step without changing your agent logic. Each site keeps its own login and re-authentication lifecycle, so a change to one domain does not require rebuilding authentication for the others.

Where authentication fits in the bigger agent identity picture

Web Bot Auth lets an agent identify itself to a website as a legitimate bot, by signing outgoing requests per RFC 9421. Managed Auth gives that agent authorized access to a specific account or domain without exposing credentials to its reasoning loop. Together, they let a website evaluate who the agent is and what it may access as separate trust decisions.

Durable access on the agentic web depends on an architecture that separates identity proof from account authorization and keeps credentials outside the model. Credential sharing removes those boundaries and makes access harder to control, monitor, and remove.

FAQs

  • What is agent identity for AI browser agents?
    • Agent identity separates three things that credential sharing collapses into one: proof of who the agent is, authorization to access a specific account, and the browser session doing the work. Kernel's Managed Auth handles the authorization layer, so the LLM reasoning about a task never receives the password that unlocked it.
  • Does the LLM ever see the password with Kernel’s Managed Auth?
    • No. Kernel encrypts credentials at rest with per-organization keys, never returns them through API responses, never writes them to logs, and never passes them to an LLM. Prompt injection and agent logs cannot expose a credential the model never receives — though an injected agent can still act within the authenticated session, which is why scope and teardown matter alongside credential isolation.
  • What happens if a site changes its login flow?
    • A login-flow change can invalidate the saved session or prevent a new login from completing. Kernel retries with exponential backoff, then surfaces the failure as a flow state with an error code such as credentials_invalid, bot_detected, or captcha_blocked, so your application can detect it and restart the flow. Your agent remains outside the login logic while you address the site-specific change.
  • How does automatic re-authentication work?
    • A scheduled health check loads the profile and confirms it is still logged in. If it is not, and the connection has a linked credential whose saved flow needs no human step, Kernel replays that flow in the background and updates the profile. Flows that require an SMS or email code, a push approval, or a manual MFA choice cannot be replayed; those connections move to NEEDS_AUTH and need a new login session. A stored totp_secret makes an authenticator-app step automatable.
  • What happens when the browser session ends?
    • The browser and its CDP endpoint are destroyed, so that session can make no further requests. The authenticated state remains in the profile by design — that is what lets the next run start already logged in. To remove access, delete the profile, along with the credential and connection if the agent should not be able to log in again. Kernel does not revoke the site-side session for you.
  • Which authentication methods are not supported?
    • Passkeys and hardware security keys. A site that requires one fails the flow with unsupported_auth_method. Switching the account to password plus TOTP makes the flow fully automatable, and most SSO providers are supported out of the box.

more articles

view all