Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 83 additions & 18 deletions auth/connection-lifecycle.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -91,44 +91,109 @@ 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. 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.

This is useful when your workflow needs to ensure a connection is authenticated *right now*:
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.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Auth-check URL is executor-internal

Medium Severity

The new copy gates verifier-first .login() behavior on a saved auth check URL and names the verifier. That artifact and component are CUA-TS internals, not part of the public connection contract, so readers cannot observe or configure them.

Additional Locations (1)
Fix in Cursor Fix in Web

Triggered by learned rule: Managed Auth docs use the canonical interaction model

Reviewed by Cursor Bugbot for commit dab983d. Configure here.


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:

<CodeGroup>
```typescript TypeScript
const state = await kernel.auth.connections.retrieve(auth.id);
async function ensureAuthenticated(connectionId: string) {
const login = await kernel.auth.connections.login(connectionId);
const events = await kernel.auth.connections.follow(connectionId);

for await (const event of events) {
if (event.event !== 'managed_auth_state') continue;

if (event.flow_status === 'SUCCESS') return;

if (state.status === 'NEEDS_AUTH') {
const login = await kernel.auth.connections.login(auth.id);
// Handle login flow as usual
if (
event.flow_step === 'AWAITING_INPUT' ||
event.flow_step === 'AWAITING_EXTERNAL_ACTION'
) {
throw new Error(`user action required at ${login.hosted_url}`);
}
}

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):
login = await kernel.auth.connections.login(connection_id)
events = await kernel.auth.connections.follow(connection_id)

async for event in events:
if event.event != "managed_auth_state":
continue

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)

if state.status == "NEEDS_AUTH":
login = await kernel.auth.connections.login(auth.id)
# Handle login flow as usual
kernel_browser = await kernel.browsers.create(
profile={"name": "github-profile"},
)
```

```go Go
state, err := client.Auth.Connections.Get(ctx, auth.ID)
login, 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
}

if event.FlowStatus == "SUCCESS" {
authenticated = true
break
}
_ = login
// Handle login flow as usual

if event.FlowStep == "AWAITING_INPUT" || event.FlowStep == "AWAITING_EXTERNAL_ACTION" {
panic("user action required at " + login.HostedURL)
}
}
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
```
</CodeGroup>

Expand Down
4 changes: 2 additions & 2 deletions auth/faq.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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()` 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.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FAQ restates lifecycle guidance

Low Severity

The FAQ answer now restates verifier-first behavior, hosted_url handoff, and the warning not to call .login() again, which already live on the lifecycle page, instead of a short pointer plus link.

Fix in Cursor Fix in Web

Triggered by learned rule: Single source of truth — no deep content duplication across pages

Reviewed by Cursor Bugbot for commit dab983d. Configure here.


## What types of flows does Managed Auth support?

Expand Down
Loading