From f750fb47b86867a2ccecd0d92a4080e4769215d2 Mon Sep 17 00:00:00 2001
From: AnnaXWang <6621137+AnnaXWang@users.noreply.github.com>
Date: Tue, 6 Oct 2026 02:52:35 +0000
Subject: [PATCH 1/2] Document pre-action managed auth login
---
auth/connection-lifecycle.mdx | 88 +++++++++++++++++++++++++++--------
auth/faq.mdx | 4 +-
2 files changed, 71 insertions(+), 21 deletions(-)
diff --git a/auth/connection-lifecycle.mdx b/auth/connection-lifecycle.mdx
index efddede2..25bc61bf 100644
--- a/auth/connection-lifecycle.mdx
+++ b/auth/connection-lifecycle.mdx
@@ -91,44 +91,94 @@ You can handle these flows in two ways:
- **Switch to TOTP** — if the site supports authenticator apps, add a `totp_secret` to your credential. KERNEL generates codes on demand, removing the need to manually provide that authenticator code. this doesn't eliminate other challenges or guarantee unattended reauthentication. if a code expires before the site accepts it, KERNEL retries with a fresh one.
- **Trigger manual re-auth** — Start a new login session and route the user through the [Hosted UI](/auth/hosted-ui) or [Programmatic](/auth/programmatic) flow.
-## Triggering re-auth manually
+## Verify authentication before starting work
-Call `.login()` on any connection to trigger authentication immediately, without waiting for the next scheduled health check. If the profile is already logged in, it returns quickly without starting a new flow. If the connection needs auth, it starts a new login session.
+Call `.login()` immediately before work that requires an authenticated session. Don't rely only on the connection's current `status`: it reflects the latest completed health check, and the website session can expire after that check.
-This is useful when your workflow needs to ensure a connection is authenticated *right now*:
+`.login()` triggers authentication on demand, without waiting for the next scheduled health check. If the profile is already logged in, the flow completes quickly. If it isn't, KERNEL starts a login session. Follow the connection until the flow reaches `SUCCESS`, then create the browser or continue the task. If the flow needs user input, send the user to the returned `hosted_url` and keep following the same connection.
+
+Use this pattern whether periodic health checks are enabled or disabled:
```typescript TypeScript
-const state = await kernel.auth.connections.retrieve(auth.id);
-
-if (state.status === 'NEEDS_AUTH') {
- const login = await kernel.auth.connections.login(auth.id);
- // Handle login flow as usual
+async function ensureAuthenticated(connectionId: string) {
+ await kernel.auth.connections.login(connectionId);
+ const events = await kernel.auth.connections.follow(connectionId);
+ let finalState;
+
+ for await (const event of events) {
+ if (event.event === 'managed_auth_state') {
+ finalState = event;
+ }
+ }
+
+ if (finalState?.flow_status !== 'SUCCESS') {
+ throw new Error('authentication did not complete successfully');
+ }
}
+
+await ensureAuthenticated(auth.id);
+
+const kernelBrowser = await kernel.browsers.create({
+ profile: { name: 'github-profile' },
+});
```
```python Python
-state = await kernel.auth.connections.retrieve(auth.id)
+async def ensure_authenticated(connection_id: str):
+ await kernel.auth.connections.login(connection_id)
+ events = await kernel.auth.connections.follow(connection_id)
+ final_state = None
+
+ async for event in events:
+ if event.event == "managed_auth_state":
+ final_state = event
-if state.status == "NEEDS_AUTH":
- login = await kernel.auth.connections.login(auth.id)
- # Handle login flow as usual
+ if not final_state or final_state.flow_status != "SUCCESS":
+ raise RuntimeError("authentication did not complete successfully")
+
+
+await ensure_authenticated(auth.id)
+
+kernel_browser = await kernel.browsers.create(
+ profile={"name": "github-profile"},
+)
```
```go Go
-state, err := client.Auth.Connections.Get(ctx, auth.ID)
+_, err := client.Auth.Connections.Login(ctx, auth.ID, kernel.AuthConnectionLoginParams{})
if err != nil {
panic(err)
}
-if state.Status == kernel.ManagedAuthStatusNeedsAuth {
- login, err := client.Auth.Connections.Login(ctx, auth.ID, kernel.AuthConnectionLoginParams{})
- if err != nil {
- panic(err)
+events := client.Auth.Connections.FollowStreaming(ctx, auth.ID)
+authenticated := false
+for events.Next() {
+ event := events.Current()
+ if event.Event != "managed_auth_state" {
+ continue
}
- _ = login
- // Handle login flow as usual
+
+ if event.FlowStatus == "SUCCESS" {
+ authenticated = true
+ }
+}
+if err := events.Err(); err != nil {
+ panic(err)
+}
+if !authenticated {
+ panic("authentication did not complete successfully")
+}
+
+kernelBrowser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{
+ Profile: shared.BrowserProfileParam{
+ Name: kernel.String("github-profile"),
+ },
+})
+if err != nil {
+ panic(err)
}
+_ = kernelBrowser
```
diff --git a/auth/faq.mdx b/auth/faq.mdx
index d87db6ec..8d6598cc 100644
--- a/auth/faq.mdx
+++ b/auth/faq.mdx
@@ -34,9 +34,9 @@ Managed Auth covers common login flows across a broad range of websites. Site-sp
Yes. Managed Auth and browser profiles are available during your trial period with the same capabilities as the plan you're trialing.
-## How do I re-authenticate a connection before the next health check?
+## How do I verify a connection before starting a task?
-Call `.login()` on the connection to trigger auth immediately. See [Triggering re-auth manually](/auth/connection-lifecycle#triggering-re-auth-manually) for the pattern.
+call `.login()` immediately before work that requires an authenticated session, then follow the connection until the flow reaches `SUCCESS`. don't gate the task only on the connection's current `status`, which reflects its latest completed health check. see [verify authentication before starting work](/auth/connection-lifecycle#verify-authentication-before-starting-work) for the full pattern.
## What types of flows does Managed Auth support?
From dab983d2f3c2f6d604961e5f2007b157a06cb551 Mon Sep 17 00:00:00 2001
From: AnnaXWang <6621137+AnnaXWang@users.noreply.github.com>
Date: Tue, 6 Oct 2026 16:41:34 +0000
Subject: [PATCH 2/2] Clarify managed auth pre-task checks
---
auth/connection-lifecycle.mdx | 47 +++++++++++++++++++++++------------
auth/faq.mdx | 2 +-
2 files changed, 32 insertions(+), 17 deletions(-)
diff --git a/auth/connection-lifecycle.mdx b/auth/connection-lifecycle.mdx
index 25bc61bf..5cb4904a 100644
--- a/auth/connection-lifecycle.mdx
+++ b/auth/connection-lifecycle.mdx
@@ -93,28 +93,34 @@ You can handle these flows in two ways:
## Verify authentication before starting work
-Call `.login()` immediately before work that requires an authenticated session. Don't rely only on the connection's current `status`: it reflects the latest completed health check, and the website session can expire after that check.
+Call `.login()` immediately before work that requires an authenticated session. Use this as a pre-task authentication check, not a replacement for the normal login flow. Don't rely only on the connection's current `status`: it reflects the latest completed health check, and the website session can expire after that check.
-`.login()` triggers authentication on demand, without waiting for the next scheduled health check. If the profile is already logged in, the flow completes quickly. If it isn't, KERNEL starts a login session. Follow the connection until the flow reaches `SUCCESS`, then create the browser or continue the task. If the flow needs user input, send the user to the returned `hosted_url` and keep following the same connection.
+For a connection with a previous successful login and saved auth check URL, `.login()` runs the verifier first. If the profile is still signed in, the flow reaches `SUCCESS` without submitting anything. If it isn't, KERNEL starts the normal login flow and uses saved credentials when available.
+
+Follow the connection until the flow reaches `SUCCESS`, then create the browser or continue the task. If the flow reaches `AWAITING_INPUT` or `AWAITING_EXTERNAL_ACTION`, stop the pre-task helper and send the user to the `hosted_url` returned by this `.login()` call. Continue that login flow; don't call `.login()` again, because a new call cancels the flow already in progress.
Use this pattern whether periodic health checks are enabled or disabled:
```typescript TypeScript
async function ensureAuthenticated(connectionId: string) {
- await kernel.auth.connections.login(connectionId);
+ const login = await kernel.auth.connections.login(connectionId);
const events = await kernel.auth.connections.follow(connectionId);
- let finalState;
for await (const event of events) {
- if (event.event === 'managed_auth_state') {
- finalState = event;
+ if (event.event !== 'managed_auth_state') continue;
+
+ if (event.flow_status === 'SUCCESS') return;
+
+ if (
+ event.flow_step === 'AWAITING_INPUT' ||
+ event.flow_step === 'AWAITING_EXTERNAL_ACTION'
+ ) {
+ throw new Error(`user action required at ${login.hosted_url}`);
}
}
- if (finalState?.flow_status !== 'SUCCESS') {
- throw new Error('authentication did not complete successfully');
- }
+ throw new Error('authentication did not complete successfully');
}
await ensureAuthenticated(auth.id);
@@ -126,16 +132,20 @@ const kernelBrowser = await kernel.browsers.create({
```python Python
async def ensure_authenticated(connection_id: str):
- await kernel.auth.connections.login(connection_id)
+ login = await kernel.auth.connections.login(connection_id)
events = await kernel.auth.connections.follow(connection_id)
- final_state = None
async for event in events:
- if event.event == "managed_auth_state":
- final_state = event
+ if event.event != "managed_auth_state":
+ continue
- if not final_state or final_state.flow_status != "SUCCESS":
- raise RuntimeError("authentication did not complete successfully")
+ if event.flow_status == "SUCCESS":
+ return
+
+ if event.flow_step in {"AWAITING_INPUT", "AWAITING_EXTERNAL_ACTION"}:
+ raise RuntimeError(f"user action required at {login.hosted_url}")
+
+ raise RuntimeError("authentication did not complete successfully")
await ensure_authenticated(auth.id)
@@ -146,7 +156,7 @@ kernel_browser = await kernel.browsers.create(
```
```go Go
-_, err := client.Auth.Connections.Login(ctx, auth.ID, kernel.AuthConnectionLoginParams{})
+login, err := client.Auth.Connections.Login(ctx, auth.ID, kernel.AuthConnectionLoginParams{})
if err != nil {
panic(err)
}
@@ -161,6 +171,11 @@ for events.Next() {
if event.FlowStatus == "SUCCESS" {
authenticated = true
+ break
+ }
+
+ if event.FlowStep == "AWAITING_INPUT" || event.FlowStep == "AWAITING_EXTERNAL_ACTION" {
+ panic("user action required at " + login.HostedURL)
}
}
if err := events.Err(); err != nil {
diff --git a/auth/faq.mdx b/auth/faq.mdx
index 8d6598cc..525ba9ce 100644
--- a/auth/faq.mdx
+++ b/auth/faq.mdx
@@ -36,7 +36,7 @@ Yes. Managed Auth and browser profiles are available during your trial period wi
## How do I verify a connection before starting a task?
-call `.login()` immediately before work that requires an authenticated session, then follow the connection until the flow reaches `SUCCESS`. don't gate the task only on the connection's current `status`, which reflects its latest completed health check. see [verify authentication before starting work](/auth/connection-lifecycle#verify-authentication-before-starting-work) for the full pattern.
+call `.login()` as a pre-task authentication check, then follow the connection until the flow reaches `SUCCESS`. when the connection has a saved auth check url, KERNEL verifies the existing session before attempting a login. if the flow pauses for user action, continue the same flow through the returned `hosted_url`; don't call `.login()` again, because that cancels the flow in progress. don't gate the task only on the connection's current `status`, which reflects its latest completed health check. see [verify authentication before starting work](/auth/connection-lifecycle#verify-authentication-before-starting-work) for the full pattern.
## What types of flows does Managed Auth support?