diff --git a/auth/agent/faq.mdx b/auth/agent/faq.mdx
deleted file mode 100644
index 8a5ca62..0000000
--- a/auth/agent/faq.mdx
+++ /dev/null
@@ -1,54 +0,0 @@
----
-title: FAQ
-description: Frequently asked questions about Agent Auth
----
-
-## How Re-Authentication Works
-
-When you save credentials, Kernel keeps your session authenticated automatically. Kernel runs periodic checks to detect expired sessions, and when logout is detected, re-auth happens automatically. When you create a browser with the profile, it's already logged in.
-
-**Initial login** uses AI to discover the login page and identify form fields. This happens once per site—credentials are never passed to the LLM.
-
-| Step | Method |
-|------|--------|
-| Discover login page | AI |
-| Identify form fields | AI |
-| Fill and submit credentials | Deterministic |
-| Handle captcha | Stealth mode + captcha solver |
-| Verify login success | AI |
-
-**Re-authentication** is fully deterministic. No AI, no guessing—just replaying the stored login flow.
-
-| Step | Method |
-|------|--------|
-| Navigate to login page | Deterministic (stored URL) |
-| Fill and submit credentials | Deterministic (stored field mapping) |
-| Handle captcha | Stealth mode + captcha solver |
-| Verify login success | AI |
-
-**Session monitoring** runs periodic auth checks (default: every hour) to detect expired sessions. When logout is detected, re-auth happens automatically.
-
-
-For sites with short session timeouts, configurable check intervals per auth agent are coming soon.
-
-
-## What authentication methods are supported?
-
-Agent Auth supports username/password authentication and most SSO providers.
-
-
-Passkey-based authentication (e.g., Google accounts with passkeys enabled) is not currently supported. If a user's SSO provider requires a passkey, the login will fail.
-
-
-## What happens if login fails?
-
-If a login attempt fails, Kernel will retry with exponential backoff. After multiple failures, the [auth invocation](/auth/agent/hosted-ui#tracking-invocation-status) will be marked as failed and you'll receive an error. Common failure reasons include:
-
-- Invalid credentials
-- Bot detection blocking the login page
-- Site structure changes that break field detection
-- Captcha that couldn't be solved
-
-## Can I use Agent Auth with any website?
-
-Agent Auth works with most websites that use standard login forms. Some sites with aggressive bot detection may require additional configuration (stealth mode, proxies). Sites that require passkeys or hardware security keys are not supported.
diff --git a/docs.json b/docs.json
index 49ffe1a..53a45fa 100644
--- a/docs.json
+++ b/docs.json
@@ -5,7 +5,13 @@
{ "source": "/careers/infra-engineer", "destination": "https://jobs.ashbyhq.com/usekernel" },
{ "source": "/careers/backend-engineer", "destination": "https://jobs.ashbyhq.com/usekernel" },
{ "source": "/careers/engineer-new-grad", "destination": "https://jobs.ashbyhq.com/usekernel" },
- { "source": "/careers/customer-engineer", "destination": "https://jobs.ashbyhq.com/usekernel" }
+ { "source": "/careers/customer-engineer", "destination": "https://jobs.ashbyhq.com/usekernel" },
+ { "source": "/auth/agent/overview", "destination": "/profiles/managed-auth/overview" },
+ { "source": "/auth/agent/hosted-ui", "destination": "/profiles/managed-auth/hosted-ui" },
+ { "source": "/auth/agent/programmatic", "destination": "/profiles/managed-auth/programmatic" },
+ { "source": "/auth/agent/faq", "destination": "/profiles/managed-auth/faq" },
+ { "source": "/browsers/profiles", "destination": "/profiles/overview" },
+ { "source": "/auth/credentials", "destination": "/profiles/credentials" }
],
"theme": "palm",
"name": "Kernel",
@@ -79,7 +85,22 @@
"pages": [
"browsers/replays",
"browsers/viewport",
- "browsers/profiles",
+ {
+ "group": "Profiles",
+ "pages": [
+ "profiles/overview",
+ {
+ "group": "Managed Auth",
+ "pages": [
+ "profiles/managed-auth/overview",
+ "profiles/managed-auth/hosted-ui",
+ "profiles/managed-auth/programmatic",
+ "profiles/credentials",
+ "profiles/managed-auth/faq"
+ ]
+ }
+ ]
+ },
"browsers/file-io",
"browsers/ssh",
"browsers/computer-controls",
@@ -121,16 +142,6 @@
}
]
},
- {
- "group": "Agent Auth",
- "pages": [
- "auth/agent/overview",
- "auth/agent/hosted-ui",
- "auth/agent/programmatic",
- "auth/credentials",
- "auth/agent/faq"
- ]
- },
{
"group": "Building your app",
"pages": [
diff --git a/integrations/1password.mdx b/integrations/1password.mdx
index e15dd59..580013c 100644
--- a/integrations/1password.mdx
+++ b/integrations/1password.mdx
@@ -1,14 +1,14 @@
---
title: "1Password"
-description: "Use credentials from your 1Password vaults for Agent Auth"
+description: "Use credentials from your 1Password vaults for Managed Auth"
---
-Connect 1Password to automatically use credentials from your existing vaults with [Agent Auth](/auth/agent/overview). No need to manually create credentials in Kernel—1Password items are discovered by domain matching.
+Connect 1Password to automatically use credentials from your existing vaults with [Managed Auth](/profiles/managed-auth/overview). No need to manually create credentials in Kernel—1Password items are discovered by domain matching.
## How It Works
1. **Connect a service account** — Add your 1Password service account token in the dashboard
-2. **Domain matching** — When Agent Auth needs credentials, it searches your connected vaults for items matching the target domain
+2. **Domain matching** — When Managed Auth needs credentials, it searches your connected vaults for items matching the target domain
3. **Automatic fill** — Credentials (including TOTP secrets) are used to complete authentication
@@ -24,37 +24,33 @@ Credentials are retrieved securely at authentication time. Values are never stor
Copy the service account token.
- Go to **Agent Auth** in the Kernel dashboard, click the **settings icon**, then select **Integrations**. Click **Connect 1Password**.
+ Go to **Profiles** in the Kernel dashboard, click the **settings icon**, then select **Integrations**. Click **Connect 1Password**.
Paste your service account token. Kernel will validate the connection and show which vaults are accessible.
-
- Start an auth invocation without specifying a `credential_id`. If 1Password has a matching item for the domain, it will be used automatically.
+
+ Create managed auth without specifying a `credential_name`. If 1Password has a matching item for the domain, it will be used automatically.
```typescript TypeScript
-const agent = await kernel.agents.auth.create({
+const auth = await kernel.profiles.auth.create({
domain: 'github.com',
profile_name: 'my-github-profile',
// No credential_name needed—1Password will provide credentials
});
-const invocation = await kernel.agents.auth.invocations.create({
- auth_agent_id: agent.id,
-});
+const login = await kernel.profiles.auth.login(auth.id);
// Credentials for github.com are automatically retrieved from 1Password
```
```python Python
-agent = await kernel.agents.auth.create(
+auth = await kernel.profiles.auth.create(
domain="github.com",
profile_name="my-github-profile",
# No credential_name needed—1Password will provide credentials
)
-invocation = await kernel.agents.auth.invocations.create(
- auth_agent_id=agent.id,
-)
+login = await kernel.profiles.auth.login(auth.id)
# Credentials for github.com are automatically retrieved from 1Password
```
@@ -81,9 +77,9 @@ If your 1Password item has a one-time password (TOTP) field configured, it will
When both Kernel credentials and 1Password are available for a domain:
-1. **Explicit credential** — If `credential_name` or `credential_id` is specified, that credential is used
+1. **Explicit credential** — If `credential_name` is specified, that credential is used
2. **1Password** — If no explicit credential, 1Password is searched
-3. **Request input** — If no credentials found, the auth agent waits for input
+3. **Request input** — If no credentials found, the flow waits for input
## Security
diff --git a/integrations/overview.mdx b/integrations/overview.mdx
index 5ee7c0f..d7808a8 100644
--- a/integrations/overview.mdx
+++ b/integrations/overview.mdx
@@ -31,7 +31,7 @@ Kernel provides detailed guides for popular agent frameworks:
- **[Val Town](/integrations/valtown)** - Serverless function runtime
- **[Vercel](https://github.com/onkernel/vercel-template)** - Deploy browser automations to Vercel
- **[Web Bot Authentication](/integrations/web-bot-auth)** - Create signed Chrome extensions for web bot authentication
-- **[1Password](/integrations/1password)** - Use credentials from your 1Password vaults for Agent Auth
+- **[1Password](/integrations/1password)** - Use credentials from your 1Password vaults for Managed Auth
## Custom Integrations
diff --git a/auth/credentials.mdx b/profiles/credentials.mdx
similarity index 70%
rename from auth/credentials.mdx
rename to profiles/credentials.mdx
index d5d9f30..6a09f98 100644
--- a/auth/credentials.mdx
+++ b/profiles/credentials.mdx
@@ -3,32 +3,31 @@ title: "Credentials"
description: "Automate authentication with stored credentials"
---
-Credentials are the automation layer for Agent Auth. Store login information securely, and Kernel handles authentication automatically—no user interaction needed.
+Credentials are the automation layer for Managed Auth. Store login information securely, and Kernel handles authentication automatically—no user interaction needed.
**Three ways to provide credentials:**
-- **Save during login** — Capture credentials when a user logs in via [Hosted UI](/auth/agent/hosted-ui) or [Programmatic](/auth/agent/programmatic)
+- **Save during login** — Capture credentials when a user logs in via [Hosted UI](/profiles/managed-auth/hosted-ui) or [Programmatic](/profiles/managed-auth/programmatic)
- **Pre-store in Kernel** — Create credentials before any login for fully headless automation
- **Connect 1Password** — Use credentials from your existing 1Password vaults
- Connect your 1Password vaults to automatically use existing credentials with Agent Auth. Credentials are matched by domain—no manual setup per site.
+ Connect your 1Password vaults to automatically use existing credentials with Managed Auth. Credentials are matched by domain—no manual setup per site.
## Save credentials during login
-Add `save_credential_as` to any invocation. The credentials entered during login are securely stored:
+Add `save_credential_as` when starting a login flow. The credentials entered during login are securely stored:
```typescript TypeScript
-const invocation = await kernel.agents.auth.invocations.create({
- auth_agent_id: agent.id,
+const login = await kernel.profiles.auth.login(auth.id, {
save_credential_as: 'my-login',
});
```
```python Python
-invocation = await kernel.agents.auth.invocations.create(
- auth_agent_id=agent.id,
+login = await kernel.profiles.auth.login(
+ auth.id,
save_credential_as="my-login",
)
```
@@ -64,33 +63,29 @@ credential = await kernel.credentials.create(
```
-Then link the credential to an auth agent:
+Then link the credential when creating a connection:
```typescript TypeScript
-const agent = await kernel.agents.auth.create({
+const auth = await kernel.profiles.auth.create({
domain: 'netflix.com',
profile_name: 'my-profile',
credential_name: credential.name,
});
-// Start invocation - logs in automatically using stored credentials
-const invocation = await kernel.agents.auth.invocations.create({
- auth_agent_id: agent.id,
-});
+// Start login - authenticates automatically using stored credentials
+const login = await kernel.profiles.auth.login(auth.id);
```
```python Python
-agent = await kernel.agents.auth.create(
+auth = await kernel.profiles.auth.create(
domain="netflix.com",
profile_name="my-profile",
credential_name=credential.name,
)
-# Start invocation - logs in automatically using stored credentials
-invocation = await kernel.agents.auth.invocations.create(
- auth_agent_id=agent.id,
-)
+# Start login - authenticates automatically using stored credentials
+login = await kernel.profiles.auth.login(auth.id)
```
@@ -140,7 +135,7 @@ const credential = await kernel.credentials.create({
},
});
-const agent = await kernel.agents.auth.create({
+const auth = await kernel.profiles.auth.create({
domain: 'target-site.com',
profile_name: 'my-profile',
credential_name: credential.name,
@@ -159,7 +154,7 @@ credential = await kernel.credentials.create(
},
)
-agent = await kernel.agents.auth.create(
+auth = await kernel.profiles.auth.create(
domain="target-site.com",
profile_name="my-profile",
credential_name=credential.name,
@@ -185,28 +180,25 @@ const credential = await kernel.credentials.create({
totp_secret: 'JBSWY3DPEHPK3PXP',
});
-const agent = await kernel.agents.auth.create({
+const auth = await kernel.profiles.auth.create({
domain: 'example.com',
profile_name: 'my-profile',
credential_name: credential.name,
});
-const invocation = await kernel.agents.auth.invocations.create({
- auth_agent_id: agent.id,
-});
+const login = await kernel.profiles.auth.login(auth.id);
// Poll until password is needed
-let state = await kernel.agents.auth.invocations.retrieve(invocation.invocation_id);
-while (state.status === 'IN_PROGRESS') {
- if (state.step === 'awaiting_input' && state.pending_fields?.length) {
+let state = await kernel.profiles.auth.retrieve(auth.id);
+while (state.flow_status === 'IN_PROGRESS') {
+ if (state.flow_step === 'AWAITING_INPUT' && state.discovered_fields?.length) {
// Only password field will be pending (email auto-filled from credential)
- await kernel.agents.auth.invocations.submit(
- invocation.invocation_id,
- { field_values: { password: 'user-provided-password' } }
- );
+ await kernel.profiles.auth.submit(auth.id, {
+ fields: { password: 'user-provided-password' }
+ });
}
await new Promise(r => setTimeout(r, 2000));
- state = await kernel.agents.auth.invocations.retrieve(invocation.invocation_id);
+ state = await kernel.profiles.auth.retrieve(auth.id);
}
// TOTP auto-submitted from credential → SUCCESS
```
@@ -219,27 +211,25 @@ credential = await kernel.credentials.create(
totp_secret="JBSWY3DPEHPK3PXP",
)
-agent = await kernel.agents.auth.create(
+auth = await kernel.profiles.auth.create(
domain="example.com",
profile_name="my-profile",
credential_name=credential.name,
)
-invocation = await kernel.agents.auth.invocations.create(
- auth_agent_id=agent.id,
-)
+login = await kernel.profiles.auth.login(auth.id)
# Poll until password is needed
-state = await kernel.agents.auth.invocations.retrieve(invocation.invocation_id)
-while state.status == "IN_PROGRESS":
- if state.step == "awaiting_input" and state.pending_fields:
+state = await kernel.profiles.auth.retrieve(auth.id)
+while state.flow_status == "IN_PROGRESS":
+ if state.flow_step == "AWAITING_INPUT" and state.discovered_fields:
# Only password field will be pending (email auto-filled from credential)
- await kernel.agents.auth.invocations.submit(
- invocation.invocation_id,
- field_values={"password": "user-provided-password"},
+ await kernel.profiles.auth.submit(
+ auth.id,
+ fields={"password": "user-provided-password"},
)
await asyncio.sleep(2)
- state = await kernel.agents.auth.invocations.retrieve(invocation.invocation_id)
+ state = await kernel.profiles.auth.retrieve(auth.id)
# TOTP auto-submitted from credential → SUCCESS
```
@@ -262,5 +252,5 @@ This is useful when you want to:
## Notes
- The `values` object is flexible—store whatever fields the login form needs (`email`, `username`, `company_id`, etc.)
-- Deleting a credential unlinks it from associated auth agents; they'll no longer auto-authenticate
+- Deleting a credential unlinks it from associated connections; they'll no longer auto-authenticate
- One credential per account—create separate credentials for different user accounts
diff --git a/profiles/managed-auth/faq.mdx b/profiles/managed-auth/faq.mdx
new file mode 100644
index 0000000..3d87455
--- /dev/null
+++ b/profiles/managed-auth/faq.mdx
@@ -0,0 +1,41 @@
+---
+title: FAQ
+description: Frequently asked questions about Managed Auth
+---
+
+## How does re-authentication work?
+
+When you link credentials to a connection, Kernel monitors the session and re-authenticates automatically when it expires. Periodic health checks (default: every hour) detect logged-out sessions and trigger re-auth in the background, so the profile stays logged in without any action on your part.
+
+
+Automatic re-authentication only works when credentials are complete and don't require human input. If login needs SMS/email OTP, push notifications, or manual MFA selection, you'll need to trigger a new login session manually.
+
+
+## How do I know if a connection needs authentication?
+
+Check the connection's `status` field:
+
+- `AUTHENTICATED` — Profile is logged in and ready to use
+- `NEEDS_AUTH` — Profile needs authentication (auto-reauth failed or isn't possible)
+
+If `status` is `NEEDS_AUTH`, you'll need to start a new login session. This happens when auto-reauth fails (e.g., password changed) or when credentials require human input.
+
+## What authentication methods are supported?
+
+Managed Auth supports username/password authentication and most SSO providers.
+
+
+Passkey-based authentication (e.g., Google accounts with passkeys enabled) is not currently supported. If a user's SSO provider requires a passkey, the login will fail.
+
+
+## What happens if login fails?
+
+If a login attempt fails, Kernel will retry with exponential backoff. After multiple failures, the [login flow](/profiles/managed-auth/hosted-ui) will be marked as failed and you'll receive an error. Common failure reasons include:
+
+- Invalid credentials
+- Bot detection blocking the login page
+- Captcha that couldn't be solved
+
+## Can I use Managed Auth with any website?
+
+Managed Auth works with any website. Sites with aggressive bot detection may require additional configuration (stealth mode, proxies). Passkeys and hardware security keys are not currently supported.
diff --git a/auth/agent/hosted-ui.mdx b/profiles/managed-auth/hosted-ui.mdx
similarity index 63%
rename from auth/agent/hosted-ui.mdx
rename to profiles/managed-auth/hosted-ui.mdx
index 2ff9dd1..5171b11 100644
--- a/auth/agent/hosted-ui.mdx
+++ b/profiles/managed-auth/hosted-ui.mdx
@@ -12,41 +12,37 @@ Use the Hosted UI when:
## Getting started
-### 1. Create an Auth Agent
+### 1. Create a Connection
-An Auth Agent represents a login session for a specific website and profile.
+A Managed Auth Connection links a profile to a domain you want to keep authenticated.
```typescript TypeScript
-const agent = await kernel.agents.auth.create({
+const auth = await kernel.profiles.auth.create({
domain: 'linkedin.com',
profile_name: 'linkedin-profile',
});
```
```python Python
-agent = await kernel.agents.auth.create(
+auth = await kernel.profiles.auth.create(
domain="linkedin.com",
profile_name="linkedin-profile",
)
```
-### 2. Start Authentication
+### 2. Start a Login Session
-Create an invocation to get the hosted login URL.
+Start a Managed Auth Session to get the hosted login URL.
```typescript TypeScript
-const invocation = await kernel.agents.auth.invocations.create({
- auth_agent_id: agent.id,
-});
+const login = await kernel.profiles.auth.login(auth.id);
```
```python Python
-invocation = await kernel.agents.auth.invocations.create(
- auth_agent_id=agent.id,
-)
+login = await kernel.profiles.auth.login(auth.id)
```
@@ -56,12 +52,12 @@ Send the user to the hosted login page:
```typescript TypeScript
-window.location.href = invocation.hosted_url;
+window.location.href = login.hosted_url;
```
```python Python
# Return the URL to your frontend
-print(f"Redirect to: {invocation.hosted_url}")
+print(f"Redirect to: {login.hosted_url}")
```
@@ -76,26 +72,26 @@ On your backend, poll until authentication completes:
```typescript TypeScript
-let state = await kernel.agents.auth.invocations.retrieve(invocation.invocation_id);
+let state = await kernel.profiles.auth.retrieve(auth.id);
-while (state.status === 'IN_PROGRESS') {
+while (state.flow_status === 'IN_PROGRESS') {
await new Promise(r => setTimeout(r, 2000));
- state = await kernel.agents.auth.invocations.retrieve(invocation.invocation_id);
+ state = await kernel.profiles.auth.retrieve(auth.id);
}
-if (state.status === 'SUCCESS') {
+if (state.status === 'AUTHENTICATED') {
console.log('Authentication successful!');
}
```
```python Python
-state = await kernel.agents.auth.invocations.retrieve(invocation.invocation_id)
+state = await kernel.profiles.auth.retrieve(auth.id)
-while state.status == "IN_PROGRESS":
+while state.flow_status == "IN_PROGRESS":
await asyncio.sleep(2)
- state = await kernel.agents.auth.invocations.retrieve(invocation.invocation_id)
+ state = await kernel.profiles.auth.retrieve(auth.id)
-if state.status == "SUCCESS":
+if state.status == "AUTHENTICATED":
print("Authentication successful!")
```
@@ -143,28 +139,26 @@ import Kernel from '@onkernel/sdk';
const kernel = new Kernel();
-// Create auth agent
-const agent = await kernel.agents.auth.create({
+// Create connection
+const auth = await kernel.profiles.auth.create({
domain: 'doordash.com',
profile_name: 'doordash-user-123',
});
// Start authentication
-const invocation = await kernel.agents.auth.invocations.create({
- auth_agent_id: agent.id,
-});
+const login = await kernel.profiles.auth.login(auth.id);
// Send user to hosted page
-console.log('Login URL:', invocation.hosted_url);
+console.log('Login URL:', login.hosted_url);
// Poll for completion
-let state = await kernel.agents.auth.invocations.retrieve(invocation.invocation_id);
-while (state.status === 'IN_PROGRESS') {
+let state = await kernel.profiles.auth.retrieve(auth.id);
+while (state.flow_status === 'IN_PROGRESS') {
await new Promise(r => setTimeout(r, 2000));
- state = await kernel.agents.auth.invocations.retrieve(invocation.invocation_id);
+ state = await kernel.profiles.auth.retrieve(auth.id);
}
-if (state.status === 'SUCCESS') {
+if (state.status === 'AUTHENTICATED') {
const browser = await kernel.browsers.create({
profile: { name: 'doordash-user-123' },
stealth: true,
@@ -181,27 +175,25 @@ import asyncio
kernel = Kernel()
-# Create auth agent
-agent = await kernel.agents.auth.create(
+# Create connection
+auth = await kernel.profiles.auth.create(
domain="doordash.com",
profile_name="doordash-user-123",
)
# Start authentication
-invocation = await kernel.agents.auth.invocations.create(
- auth_agent_id=agent.id,
-)
+login = await kernel.profiles.auth.login(auth.id)
# Send user to hosted page
-print(f"Login URL: {invocation.hosted_url}")
+print(f"Login URL: {login.hosted_url}")
# Poll for completion
-state = await kernel.agents.auth.invocations.retrieve(invocation.invocation_id)
-while state.status == "IN_PROGRESS":
+state = await kernel.profiles.auth.retrieve(auth.id)
+while state.flow_status == "IN_PROGRESS":
await asyncio.sleep(2)
- state = await kernel.agents.auth.invocations.retrieve(invocation.invocation_id)
+ state = await kernel.profiles.auth.retrieve(auth.id)
-if state.status == "SUCCESS":
+if state.status == "AUTHENTICATED":
browser = await kernel.browsers.create(
profile={"name": "doordash-user-123"},
stealth=True,
@@ -222,29 +214,28 @@ Capture the user's credentials during login so future sessions can re-authentica
```typescript TypeScript
-const invocation = await kernel.agents.auth.invocations.create({
- auth_agent_id: agent.id,
+const login = await kernel.profiles.auth.login(auth.id, {
save_credential_as: 'my-saved-creds',
});
```
```python Python
-invocation = await kernel.agents.auth.invocations.create(
- auth_agent_id=agent.id,
+login = await kernel.profiles.auth.login(
+ auth.id,
save_credential_as="my-saved-creds",
)
```
-After successful login, future invocations for this agent will automatically use the saved credentials—no user interaction needed. See [Credentials](/auth/credentials) for more on automated authentication.
+After successful login, future login sessions for this connection will automatically use the saved credentials—no user interaction needed. See [Credentials](/profiles/credentials) for more on automated authentication.
### Custom Login URL
-If the site's login page isn't at the default location, specify it when creating the agent:
+If the site's login page isn't at the default location, specify it when creating the connection:
```typescript TypeScript
-const agent = await kernel.agents.auth.create({
+const auth = await kernel.profiles.auth.create({
domain: 'example.com',
profile_name: 'my-profile',
login_url: 'https://example.com/auth/signin',
@@ -252,7 +243,7 @@ const agent = await kernel.agents.auth.create({
```
```python Python
-agent = await kernel.agents.auth.create(
+auth = await kernel.profiles.auth.create(
domain="example.com",
profile_name="my-profile",
login_url="https://example.com/auth/signin",
@@ -266,7 +257,7 @@ For sites with "Sign in with Google/GitHub/Microsoft", add the OAuth provider's
```typescript TypeScript
-const agent = await kernel.agents.auth.create({
+const auth = await kernel.profiles.auth.create({
domain: 'example.com',
profile_name: 'my-profile',
allowed_domains: ['accounts.google.com', 'google.com'],
@@ -274,7 +265,7 @@ const agent = await kernel.agents.auth.create({
```
```python Python
-agent = await kernel.agents.auth.create(
+auth = await kernel.profiles.auth.create(
domain="example.com",
profile_name="my-profile",
allowed_domains=["accounts.google.com", "google.com"],
@@ -286,23 +277,23 @@ The user can click the SSO button on the hosted page, complete OAuth with the pr
### Post-Login URL
-After successful authentication, retrieve the auth agent to get `post_login_url`—the page where the login landed. Use this to start your automation from the right place:
+After successful authentication, retrieve the connection to get `post_login_url`—the page where the login landed. Use this to start your automation from the right place:
```typescript TypeScript
-const authAgent = await kernel.agents.auth.retrieve(agent.id);
+const managedAuth = await kernel.profiles.auth.retrieve(auth.id);
-if (authAgent.post_login_url) {
- await page.goto(authAgent.post_login_url);
+if (managedAuth.post_login_url) {
+ await page.goto(managedAuth.post_login_url);
// Start automation from the dashboard/home page
}
```
```python Python
-auth_agent = await kernel.agents.auth.retrieve(agent.id)
+managed_auth = await kernel.profiles.auth.retrieve(auth.id)
-if auth_agent.post_login_url:
- await page.goto(auth_agent.post_login_url)
+if managed_auth.post_login_url:
+ await page.goto(managed_auth.post_login_url)
# Start automation from the dashboard/home page
```
diff --git a/auth/agent/overview.mdx b/profiles/managed-auth/overview.mdx
similarity index 57%
rename from auth/agent/overview.mdx
rename to profiles/managed-auth/overview.mdx
index 56bd890..696f285 100644
--- a/auth/agent/overview.mdx
+++ b/profiles/managed-auth/overview.mdx
@@ -4,72 +4,73 @@ description: "Create authenticated browser sessions for your automations"
---
- Agent Auth is currently in public beta. Features are subject to change.
+ Managed Auth is currently in public beta. Features are subject to change.
-Agent Auth creates and maintains authenticated browser profiles for your automations. Store credentials once, and Kernel monitors auth state and re-authenticates automatically when needed. When you launch a browser with the profile, you're already logged in and ready to go.
+Managed Auth creates and maintains authenticated browser profiles for your automations. Store credentials once, and Kernel monitors auth state and re-authenticates automatically when needed. When you launch a browser with the profile, you're already logged in and ready to go.
## How It Works
-
- An **Auth Agent** represents a login session for a specific website and profile. Create one for each domain + profile combination.
+
+ A **Managed Auth Connection** links a profile to a domain. Create one for each domain + profile combination you want to keep authenticated.
```typescript TypeScript
-const agent = await kernel.agents.auth.create({
+const auth = await kernel.profiles.auth.create({
domain: 'netflix.com',
profile_name: 'netflix-user-123',
});
```
```python Python
-agent = await kernel.agents.auth.create(
+auth = await kernel.profiles.auth.create(
domain="netflix.com",
profile_name="netflix-user-123",
)
```
-
- Start the login flow. Users provide credentials via the hosted page (or your own UI).
+
+ A **Managed Auth Session** is the login flow. Start one to authenticate—users provide credentials via the hosted page (or your own UI).
```typescript TypeScript
-const invocation = await kernel.agents.auth.invocations.create({
- auth_agent_id: agent.id,
+const login = await kernel.profiles.auth.login(auth.id, {
+ save_credential_as: 'my-netflix-creds', // Optional: save for auto-reauth
});
// Send user to login page
-console.log('Login URL:', invocation.hosted_url);
+console.log('Login URL:', login.hosted_url);
// Poll until complete
-let state = await kernel.agents.auth.invocations.retrieve(invocation.invocation_id);
-while (state.status === 'IN_PROGRESS') {
+let state = await kernel.profiles.auth.retrieve(auth.id);
+while (state.flow_status === 'IN_PROGRESS') {
await new Promise(r => setTimeout(r, 2000));
- state = await kernel.agents.auth.invocations.retrieve(invocation.invocation_id);
+ state = await kernel.profiles.auth.retrieve(auth.id);
}
-if (state.status === 'SUCCESS') {
+if (state.status === 'AUTHENTICATED') {
console.log('Authenticated!');
}
```
```python Python
-invocation = await kernel.agents.auth.invocations.create(
- auth_agent_id=agent.id,
+login = await kernel.profiles.auth.login(
+ auth.id,
+ save_credential_as="my-netflix-creds", # Optional: save for auto-reauth
)
# Send user to login page
-print(f"Login URL: {invocation.hosted_url}")
+print(f"Login URL: {login.hosted_url}")
# Poll until complete
-state = await kernel.agents.auth.invocations.retrieve(invocation.invocation_id)
-while state.status == "IN_PROGRESS":
+state = await kernel.profiles.auth.retrieve(auth.id)
+while state.flow_status == "IN_PROGRESS":
await asyncio.sleep(2)
- state = await kernel.agents.auth.invocations.retrieve(invocation.invocation_id)
+ state = await kernel.profiles.auth.retrieve(auth.id)
-if state.status == "SUCCESS":
+if state.status == "AUTHENTICATED":
print("Authenticated!")
```
@@ -99,19 +100,19 @@ await page.goto("https://netflix.com")
```
- For fully automated flows, link [Credentials](/auth/credentials) to enable re-authentication without user input.
+ For fully automated flows, link [Credentials](/profiles/credentials) to enable re-authentication without user input.
## Choose Your Integration
-
+
**Start here** - Simplest integration
Redirect users to Kernel's hosted page. Add features incrementally: save credentials for auto-reauth, custom login URLs, SSO support.
-
+
**Full control** - Custom UI or headless
Build your own credential collection. Handle login fields, SSO buttons, MFA selection, and external actions (push notifications, security keys).
@@ -119,12 +120,12 @@ await page.goto("https://netflix.com")
-Layer in [Credentials](/auth/credentials) to enable fully automated re-authentication when sessions expire—no user interaction needed.
+Layer in [Credentials](/profiles/credentials) to enable fully automated re-authentication when sessions expire—no user interaction needed.
-## Why Agent Auth?
+## Why Managed Auth?
-The most valuable workflows live behind logins. Agent Auth provides:
+The most valuable workflows live behind logins. Managed Auth provides:
- **Works on any website** - Login pages discovered and handled automatically
- **SSO/OAuth support** - "Sign in with Google/GitHub/Microsoft" buttons work out of the box via `allowed_domains`
diff --git a/auth/agent/programmatic.mdx b/profiles/managed-auth/programmatic.mdx
similarity index 51%
rename from auth/agent/programmatic.mdx
rename to profiles/managed-auth/programmatic.mdx
index c41d7e3..f105ce0 100644
--- a/auth/agent/programmatic.mdx
+++ b/profiles/managed-auth/programmatic.mdx
@@ -13,11 +13,11 @@ Use the Programmatic flow when:
## How It Works
-
- Same as [Hosted UI](/auth/agent/hosted-ui)
+
+ Same as [Hosted UI](/profiles/managed-auth/hosted-ui)
- Poll until `step` becomes `awaiting_input`, then submit credentials
+ Poll until `flow_step` becomes `AWAITING_INPUT`, then submit credentials
If more fields appear (2FA code), submit again—same loop handles it
@@ -26,37 +26,33 @@ Use the Programmatic flow when:
## Getting started
-### 1. Create an Auth Agent
+### 1. Create a Connection
```typescript TypeScript
-const agent = await kernel.agents.auth.create({
+const auth = await kernel.profiles.auth.create({
domain: 'github.com',
profile_name: 'github-profile',
});
```
```python Python
-agent = await kernel.agents.auth.create(
+auth = await kernel.profiles.auth.create(
domain="github.com",
profile_name="github-profile",
)
```
-### 2. Start Authentication
+### 2. Start a Login Session
```typescript TypeScript
-const invocation = await kernel.agents.auth.invocations.create({
- auth_agent_id: agent.id,
-});
+const login = await kernel.profiles.auth.login(auth.id);
```
```python Python
-invocation = await kernel.agents.auth.invocations.create(
- auth_agent_id=agent.id,
-)
+login = await kernel.profiles.auth.login(auth.id)
```
@@ -64,15 +60,14 @@ To save credentials for automatic re-authentication:
```typescript TypeScript
-const invocation = await kernel.agents.auth.invocations.create({
- auth_agent_id: agent.id,
+const login = await kernel.profiles.auth.login(auth.id, {
save_credential_as: 'my-saved-creds',
});
```
```python Python
-invocation = await kernel.agents.auth.invocations.create(
- auth_agent_id=agent.id,
+login = await kernel.profiles.auth.login(
+ auth.id,
save_credential_as="my-saved-creds",
)
```
@@ -84,54 +79,48 @@ A single loop handles everything—initial login, 2FA, and completion:
```typescript TypeScript
-let state = await kernel.agents.auth.invocations.retrieve(invocation.invocation_id);
+let state = await kernel.profiles.auth.retrieve(auth.id);
-while (state.status === 'IN_PROGRESS') {
+while (state.flow_status === 'IN_PROGRESS') {
// Submit when fields are ready (login or 2FA)
- if (state.step === 'awaiting_input' && state.pending_fields?.length) {
- const fieldValues = getCredentialsForFields(state.pending_fields);
- await kernel.agents.auth.invocations.submit(
- invocation.invocation_id,
- { field_values: fieldValues }
- );
+ if (state.flow_step === 'AWAITING_INPUT' && state.discovered_fields?.length) {
+ const fieldValues = getCredentialsForFields(state.discovered_fields);
+ await kernel.profiles.auth.submit(auth.id, { fields: fieldValues });
}
await new Promise(r => setTimeout(r, 2000));
- state = await kernel.agents.auth.invocations.retrieve(invocation.invocation_id);
+ state = await kernel.profiles.auth.retrieve(auth.id);
}
-if (state.status === 'SUCCESS') {
+if (state.status === 'AUTHENTICATED') {
console.log('Authentication successful!');
}
```
```python Python
-state = await kernel.agents.auth.invocations.retrieve(invocation.invocation_id)
+state = await kernel.profiles.auth.retrieve(auth.id)
-while state.status == "IN_PROGRESS":
+while state.flow_status == "IN_PROGRESS":
# Submit when fields are ready (login or 2FA)
- if state.step == "awaiting_input" and state.pending_fields:
- field_values = get_credentials_for_fields(state.pending_fields)
- await kernel.agents.auth.invocations.submit(
- invocation.invocation_id,
- field_values=field_values,
- )
+ if state.flow_step == "AWAITING_INPUT" and state.discovered_fields:
+ field_values = get_credentials_for_fields(state.discovered_fields)
+ await kernel.profiles.auth.submit(auth.id, fields=field_values)
await asyncio.sleep(2)
- state = await kernel.agents.auth.invocations.retrieve(invocation.invocation_id)
+ state = await kernel.profiles.auth.retrieve(auth.id)
-if state.status == "SUCCESS":
+if state.status == "AUTHENTICATED":
print("Authentication successful!")
```
-The `pending_fields` array tells you what the login form needs:
+The `discovered_fields` array tells you what the login form needs:
```typescript
-// Example pending_fields for login
+// Example discovered_fields for login
[{ name: 'username', type: 'text' }, { name: 'password', type: 'password' }]
-// Example pending_fields for 2FA
+// Example discovered_fields for 2FA
[{ name: 'otp', type: 'code' }]
```
@@ -143,45 +132,41 @@ import Kernel from '@onkernel/sdk';
const kernel = new Kernel();
-// Create auth agent
-const agent = await kernel.agents.auth.create({
+// Create connection
+const auth = await kernel.profiles.auth.create({
domain: 'github.com',
profile_name: 'github-profile',
});
-const invocation = await kernel.agents.auth.invocations.create({
- auth_agent_id: agent.id,
-});
+const login = await kernel.profiles.auth.login(auth.id);
// Single polling loop handles login + 2FA
-let state = await kernel.agents.auth.invocations.retrieve(invocation.invocation_id);
+let state = await kernel.profiles.auth.retrieve(auth.id);
-while (state.status === 'IN_PROGRESS') {
- if (state.step === 'awaiting_input' && state.pending_fields?.length) {
+while (state.flow_status === 'IN_PROGRESS') {
+ if (state.flow_step === 'AWAITING_INPUT' && state.discovered_fields?.length) {
// Check what fields are needed
- const fieldNames = state.pending_fields.map(f => f.name);
+ const fieldNames = state.discovered_fields.map(f => f.name);
if (fieldNames.includes('username')) {
// Initial login
- await kernel.agents.auth.invocations.submit(
- invocation.invocation_id,
- { field_values: { username: 'my-username', password: 'my-password' } }
- );
+ await kernel.profiles.auth.submit(auth.id, {
+ fields: { username: 'my-username', password: 'my-password' }
+ });
} else {
// 2FA or additional fields
const code = await promptUserForCode();
- await kernel.agents.auth.invocations.submit(
- invocation.invocation_id,
- { field_values: { [state.pending_fields[0].name]: code } }
- );
+ await kernel.profiles.auth.submit(auth.id, {
+ fields: { [state.discovered_fields[0].name]: code }
+ });
}
}
await new Promise(r => setTimeout(r, 2000));
- state = await kernel.agents.auth.invocations.retrieve(invocation.invocation_id);
+ state = await kernel.profiles.auth.retrieve(auth.id);
}
-if (state.status === 'SUCCESS') {
+if (state.status === 'AUTHENTICATED') {
console.log('Authentication successful!');
const browser = await kernel.browsers.create({
@@ -200,42 +185,40 @@ import asyncio
kernel = Kernel()
-# Create auth agent
-agent = await kernel.agents.auth.create(
+# Create connection
+auth = await kernel.profiles.auth.create(
domain="github.com",
profile_name="github-profile",
)
-invocation = await kernel.agents.auth.invocations.create(
- auth_agent_id=agent.id,
-)
+login = await kernel.profiles.auth.login(auth.id)
# Single polling loop handles login + 2FA
-state = await kernel.agents.auth.invocations.retrieve(invocation.invocation_id)
+state = await kernel.profiles.auth.retrieve(auth.id)
-while state.status == "IN_PROGRESS":
- if state.step == "awaiting_input" and state.pending_fields:
+while state.flow_status == "IN_PROGRESS":
+ if state.flow_step == "AWAITING_INPUT" and state.discovered_fields:
# Check what fields are needed
- field_names = [f["name"] for f in state.pending_fields]
+ field_names = [f["name"] for f in state.discovered_fields]
if "username" in field_names:
# Initial login
- await kernel.agents.auth.invocations.submit(
- invocation.invocation_id,
- field_values={"username": "my-username", "password": "my-password"},
+ await kernel.profiles.auth.submit(
+ auth.id,
+ fields={"username": "my-username", "password": "my-password"},
)
else:
# 2FA or additional fields
code = input("Enter code: ")
- await kernel.agents.auth.invocations.submit(
- invocation.invocation_id,
- field_values={state.pending_fields[0]["name"]: code},
+ await kernel.profiles.auth.submit(
+ auth.id,
+ fields={state.discovered_fields[0]["name"]: code},
)
await asyncio.sleep(2)
- state = await kernel.agents.auth.invocations.retrieve(invocation.invocation_id)
+ state = await kernel.profiles.auth.retrieve(auth.id)
-if state.status == "SUCCESS":
+if state.status == "AUTHENTICATED":
print("Authentication successful!")
browser = await kernel.browsers.create(
@@ -250,7 +233,7 @@ if state.status == "SUCCESS":
## Handling Different Input Types
-The basic polling loop handles `pending_fields`, but login pages can require other input types too.
+The basic polling loop handles `discovered_fields`, but login pages can require other input types too.
### SSO Buttons
@@ -265,10 +248,9 @@ if (state.pending_sso_buttons?.length) {
}
// Submit the selected SSO button
- await kernel.agents.auth.invocations.submit(
- invocation.invocation_id,
- { sso_button: state.pending_sso_buttons[0].selector }
- );
+ await kernel.profiles.auth.submit(auth.id, {
+ sso_button_selector: state.pending_sso_buttons[0].selector
+ });
}
```
@@ -279,15 +261,15 @@ if state.pending_sso_buttons:
print(f"{btn['provider']}: {btn['label']}")
# Submit the selected SSO button
- await kernel.agents.auth.invocations.submit(
- invocation.invocation_id,
- sso_button=state.pending_sso_buttons[0]["selector"],
+ await kernel.profiles.auth.submit(
+ auth.id,
+ sso_button_selector=state.pending_sso_buttons[0]["selector"],
)
```
-Remember to set `allowed_domains` on the agent to include the OAuth provider's domain (e.g., `accounts.google.com`).
+Remember to set `allowed_domains` on the connection to include the OAuth provider's domain (e.g., `accounts.google.com`).
### MFA Selection
@@ -303,10 +285,9 @@ if (state.mfa_options?.length) {
}
// Submit the selected MFA method
- await kernel.agents.auth.invocations.submit(
- invocation.invocation_id,
- { selected_mfa_type: 'sms' }
- );
+ await kernel.profiles.auth.submit(auth.id, {
+ mfa_option_id: 'sms'
+ });
}
```
@@ -317,22 +298,22 @@ if state.mfa_options:
print(f"{opt['type']}: {opt['label']}")
# Submit the selected MFA method
- await kernel.agents.auth.invocations.submit(
- invocation.invocation_id,
- selected_mfa_type="sms",
+ await kernel.profiles.auth.submit(
+ auth.id,
+ mfa_option_id="sms",
)
```
-After selecting an MFA method, the flow continues—poll for `pending_fields` to submit the code, or handle external actions for push/security key.
+After selecting an MFA method, the flow continues—poll for `discovered_fields` to submit the code, or handle external actions for push/security key.
### External Actions (Push, Security Key)
-When the site requires an action outside the browser (push notification, security key tap), the step becomes `awaiting_external_action`:
+When the site requires an action outside the browser (push notification, security key tap), the step becomes `AWAITING_EXTERNAL_ACTION`:
```typescript TypeScript
-if (state.step === 'awaiting_external_action') {
+if (state.flow_step === 'AWAITING_EXTERNAL_ACTION') {
// Show the message to the user
console.log(state.external_action_message);
// e.g., "Check your phone for a push notification"
@@ -342,7 +323,7 @@ if (state.step === 'awaiting_external_action') {
```
```python Python
-if state.step == "awaiting_external_action":
+if state.flow_step == "AWAITING_EXTERNAL_ACTION":
# Show the message to the user
print(state.external_action_message)
# e.g., "Check your phone for a push notification"
@@ -353,23 +334,45 @@ if state.step == "awaiting_external_action":
## Step Reference
-The `step` field indicates what the flow is waiting for:
+The `flow_step` field indicates what the flow is waiting for:
| Step | Description |
|------|-------------|
-| `discovering` | Finding the login page and analyzing it |
-| `awaiting_input` | Waiting for field values, SSO button click, or MFA selection |
-| `submitting` | Processing submitted values |
-| `awaiting_external_action` | Waiting for push approval, security key, etc. |
+| `DISCOVERING` | Finding the login page and analyzing it |
+| `AWAITING_INPUT` | Waiting for field values, SSO button click, or MFA selection |
+| `SUBMITTING` | Processing submitted values |
+| `AWAITING_EXTERNAL_ACTION` | Waiting for push approval, security key, etc. |
+| `COMPLETED` | Flow has finished |
## Status Reference
-The `status` field indicates the overall invocation state:
+The `flow_status` field indicates the current flow state:
| Status | Description |
|--------|-------------|
| `IN_PROGRESS` | Authentication is ongoing—keep polling |
| `SUCCESS` | Login completed, profile saved |
| `FAILED` | Login failed (check `error_message`) |
-| `EXPIRED` | Invocation timed out (5 minutes) |
-| `CANCELED` | Invocation was canceled |
+| `EXPIRED` | Flow timed out (5 minutes) |
+| `CANCELED` | Flow was canceled |
+
+The `status` field indicates the overall connection state:
+
+| Status | Description |
+|--------|-------------|
+| `AUTHENTICATED` | Profile is logged in and ready to use |
+| `NEEDS_AUTH` | Profile needs authentication |
+
+## Real-Time Updates with SSE
+
+For real-time UIs, you can stream login flow events via Server-Sent Events instead of polling:
+
+```
+GET /profiles/auth/{id}/events
+```
+
+The stream delivers `managed_auth_state` events with the same fields as polling (`flow_status`, `flow_step`, `discovered_fields`, etc.) and terminates automatically when the flow reaches a terminal state.
+
+
+Polling is recommended for most integrations. SSE is useful when building real-time UIs that need instant updates without polling delays.
+
diff --git a/browsers/profiles.mdx b/profiles/overview.mdx
similarity index 99%
rename from browsers/profiles.mdx
rename to profiles/overview.mdx
index 004ddb2..0fff88d 100644
--- a/browsers/profiles.mdx
+++ b/profiles/overview.mdx
@@ -1,5 +1,5 @@
---
-title: "Profiles"
+title: "Overview"
description: "Persist and reuse browser session state (cookies, local storage) across sessions"
---