|
| 1 | +--- |
| 2 | +title: "Connection Lifecycle" |
| 3 | +description: "How connections stay authenticated, and what to do when one breaks" |
| 4 | +--- |
| 5 | + |
| 6 | +Once a Managed Auth connection is `AUTHENTICATED`, Kernel runs periodic health checks and automatic re-authentication to keep the session valid. This page covers the runtime lifecycle of a connection: how the check-and-reauth loop works, how to tune it, what blocks auto-reauth, and how to debug a connection that won't stay logged in. |
| 7 | + |
| 8 | +## The lifecycle |
| 9 | + |
| 10 | +After the initial login, every connection moves through this loop: |
| 11 | + |
| 12 | +<Steps> |
| 13 | + <Step title="Health check"> |
| 14 | + On a configurable cadence, Kernel spins up a browser with the profile and verifies the session is still logged in. If it is, nothing else happens until the next check. |
| 15 | + </Step> |
| 16 | + <Step title="Auto-reauth (if eligible)"> |
| 17 | + If the check finds the session expired and the connection's `can_reauth` is `true`, Kernel runs the saved login flow with the stored credentials in the background. A successful login resets the loop. |
| 18 | + </Step> |
| 19 | + <Step title="NEEDS_AUTH (if not eligible, or auto-reauth fails)"> |
| 20 | + If auto-reauth isn't possible — credentials aren't linked, the saved flow requires human input, or the login keeps failing — the connection's `status` flips to `NEEDS_AUTH` and a new login session is required. |
| 21 | + </Step> |
| 22 | +</Steps> |
| 23 | + |
| 24 | +## Cadence |
| 25 | + |
| 26 | +Health checks run on a configurable interval. Your plan sets the minimum: |
| 27 | + |
| 28 | +| Plan | Minimum interval | |
| 29 | +|------|------------------| |
| 30 | +| Hobbyist | 1 hour | |
| 31 | +| Start-Up | 20 minutes | |
| 32 | +| Enterprise | Fully configurable (as low as 5 minutes) | |
| 33 | + |
| 34 | +You can raise the interval above your plan's minimum, but not below it. Update it with `health_check_interval` (in seconds) — changes take effect immediately, so the next check uses the new value: |
| 35 | + |
| 36 | +<CodeGroup> |
| 37 | +```typescript TypeScript |
| 38 | +await kernel.auth.connections.update(auth.id, { |
| 39 | + health_check_interval: 1800, // 30 minutes |
| 40 | +}); |
| 41 | +``` |
| 42 | + |
| 43 | +```python Python |
| 44 | +await kernel.auth.connections.update( |
| 45 | + auth.id, |
| 46 | + health_check_interval=1800, # 30 minutes |
| 47 | +) |
| 48 | +``` |
| 49 | +</CodeGroup> |
| 50 | + |
| 51 | +### Sessions that expire faster than the interval |
| 52 | + |
| 53 | +Kernel keeps re-authenticating even when every health check finds the session expired. A successful login resets the auto-reauth state, so a site whose session TTL is shorter than your health check interval is re-authenticated on every cycle rather than being given up on. |
| 54 | + |
| 55 | +If you're seeing the connection flip to `NEEDS_AUTH` frequently and want shorter detection windows, lower `health_check_interval` toward your plan's minimum. |
| 56 | + |
| 57 | +## Can this connection auto-reauth? |
| 58 | + |
| 59 | +Check the `can_reauth` boolean on a connection. It's `true` only when **both** of these hold: |
| 60 | + |
| 61 | +1. **A credential is linked** — stored in Kernel or sourced via [1Password](/integrations/1password). |
| 62 | +2. **No external action is required** — the saved login flow doesn't need a human (no SMS/email OTP, no push notification, no manual MFA selection). |
| 63 | + |
| 64 | +If either fails, the connection will move to `NEEDS_AUTH` on the next expired session and wait for a fresh login. |
| 65 | + |
| 66 | +### External actions that block auto-reauth |
| 67 | + |
| 68 | +After a successful login, Kernel saves the login flow. If that flow includes steps that require human action, the connection can't auto-reauth because those steps can't be replayed without user input. |
| 69 | + |
| 70 | +If your flow requires one of these, you can still automate around it: |
| 71 | + |
| 72 | +- **Switch to TOTP** — If the site supports authenticator apps, add a `totp_secret` to your credential. Codes are generated on demand, so the flow no longer needs external action. If a code expires before the site accepts it, Kernel retries with a fresh one. |
| 73 | +- **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. |
| 74 | + |
| 75 | +## Triggering re-auth manually |
| 76 | + |
| 77 | +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. |
| 78 | + |
| 79 | +This is useful when your workflow needs to ensure a connection is authenticated *right now*: |
| 80 | + |
| 81 | +<CodeGroup> |
| 82 | +```typescript TypeScript |
| 83 | +const state = await kernel.auth.connections.retrieve(auth.id); |
| 84 | + |
| 85 | +if (state.status === 'NEEDS_AUTH') { |
| 86 | + const login = await kernel.auth.connections.login(auth.id); |
| 87 | + // Handle login flow as usual |
| 88 | +} |
| 89 | +``` |
| 90 | + |
| 91 | +```python Python |
| 92 | +state = await kernel.auth.connections.retrieve(auth.id) |
| 93 | + |
| 94 | +if state.status == "NEEDS_AUTH": |
| 95 | + login = await kernel.auth.connections.login(auth.id) |
| 96 | + # Handle login flow as usual |
| 97 | +``` |
| 98 | +</CodeGroup> |
| 99 | + |
| 100 | +## When a login fails |
| 101 | + |
| 102 | +If a login attempt fails — whether triggered by a health check, an auto-reauth, or a manual `.login()` — Kernel retries with exponential backoff. After repeated failures the flow is marked failed and the connection surfaces an error code on `flow_status`. |
| 103 | + |
| 104 | +Common codes: |
| 105 | + |
| 106 | +| Code | Meaning | |
| 107 | +|------|---------| |
| 108 | +| `credentials_invalid` | The stored or submitted credentials were rejected by the site. | |
| 109 | +| `bot_detected` | The login page blocked the session as automated. | |
| 110 | +| `captcha_blocked` | A CAPTCHA was presented and couldn't be solved. | |
| 111 | +| `unsupported_auth_method` | The site required a method Kernel doesn't currently support (e.g. passkeys). | |
| 112 | + |
| 113 | +See the [API reference](https://kernel.sh/docs/api-reference/managed-auth/start-login-flow) for the full list. |
| 114 | + |
| 115 | +### Recovering |
| 116 | + |
| 117 | +- **`credentials_invalid`** — Update the linked [credential](/auth/credentials) and call `.login()` to re-run the flow. |
| 118 | +- **`bot_detected` / `captcha_blocked`** — Pin the connection to a cleaner [proxy](/auth/configuration#custom-proxy) (ISP or custom). For aggressive sites, also enable stealth and review the [bot detection guide](/browsers/bot-detection/overview). |
| 119 | +- **`unsupported_auth_method`** — Switch the account to a supported sign-in method (e.g. password + TOTP instead of a passkey) and re-link the credential. |
| 120 | + |
| 121 | +## Debugging a flaky connection |
| 122 | + |
| 123 | +Two tools handle most investigations: |
| 124 | + |
| 125 | +1. **Dashboard live view** — The **Browser Sessions** tab in the Kernel dashboard shows every auth browser session (logins, health checks, reauths) with a live view. Watch a session in real time to see exactly where it's getting stuck. |
| 126 | + |
| 127 | +2. **Session recordings** — To record only the next single login attempt without recording subsequent health checks and reauths, pass `record_session: true` on `.login()`: |
| 128 | + |
| 129 | +<CodeGroup> |
| 130 | +```typescript TypeScript |
| 131 | +const login = await kernel.auth.connections.login(auth.id, { |
| 132 | + record_session: true, |
| 133 | +}); |
| 134 | +``` |
| 135 | + |
| 136 | +```python Python |
| 137 | +login = await kernel.auth.connections.login( |
| 138 | + auth.id, |
| 139 | + record_session=True, |
| 140 | +) |
| 141 | +``` |
| 142 | +</CodeGroup> |
| 143 | + |
| 144 | +To record every auth session on the connection (logins, health checks, and reauths), set `record_session: true` connection-wide — see [Record Sessions for Debugging](/auth/configuration#record-sessions-for-debugging). |
| 145 | + |
| 146 | +## See also |
| 147 | + |
| 148 | +- [Connection Configuration](/auth/configuration) — `health_check_interval`, `proxy`, `record_session`, and other shared options |
| 149 | +- [Credentials](/auth/credentials) — what gets stored and how it powers auto-reauth |
| 150 | +- [FAQ](/auth/faq) — quick answers to common questions |
0 commit comments