---
title: "Magic Link Worked and Then claude.ai/logout?involuntary=1 Showed Up"
canonical: https://dxdev.com/blog/chrome-for-testing-auth-boundary/
datePublished: 2026-08-27
---
Both claude.ai session URLs bounced to `claude.ai/logout?involuntary=1` before anyone had typed anything, and the login page carried `returnTo=%2Fcode%2Fsession_...`, so the redirect was clearly deliberate.

The setup was a [pool of 25 Chrome for Testing slots](/blog/stopped-babysitting-the-browser-then-built-the-missing-part/) (150.0.7871.24), each with its own `--user-data-dir` and debug port, so agent sessions could drive browsers without touching each other. We had pointed two remote-control session URLs at that pool. A stable Chrome 151 profile on port 9222 sat next to it, mostly unused for this.

## Chasing a bot block that wasn't there

Chrome for Testing announces itself. It paints an "only for automated testing" banner on every window and sets automation signals. We [read the bounce as bot detection](/blog/cursor-process-tree-sessions/) and went after the banner and the fingerprint.

We added `--test-type` to the launch flags, which is supposed to suppress the banner. It didn't. The banner stayed on every window. We also spent a stretch reading up on undetected-browser tooling, and it produced a brief recommending nodriver for unattended work. That fix was aimed at a problem the browser didn't have.

What broke the theory was that the magic link worked. We requested a sign-in link, clicked it, and the page really did sign in. Then `/code` and `/new` both kicked us back to logout. A bot wall would have stopped us at the door. This let us in and evicted us one navigation later.

## device_key_missing

The kick-out reason was `device_key_missing`, an elevated-auth check on the Claude Code surfaces. Plain claude.ai auth is satisfied by the cookie. `/code` and `/new` additionally want a device key, and Chrome for Testing could not provide one. Every time we measured it, the sequence was the same:

1. Magic link signs in.
2. `/code` or `/new` loads.
3. Redirect to `logout?involuntary=1`.

We measured it twice on the same day, to make sure we weren't looking at a stale cookie.

Then we ran the same test in the stable Chrome on 9222 (151.0.7922.169, profile `chrome-claude`). We navigated to a session URL from a cold profile and got the login page with `returnTo` intact. We filled the email field through CDP, submitted, and signed in with the magic link. It held. `/code` loaded and stayed loaded.

One detail cost us a retry. Our first attempt to read the page afterward threw `SyntaxError: Invalid regular expression: missing /`, because the JS we passed to `Runtime.evaluate` had its backslashes eaten by the shell heredoc. The fault was in our quoting, and we fixed it before reading the result.

## One long-lived profile for claude.ai

We wrote the rule into the repo's `CLAUDE.md` so the next agent doesn't rediscover it:

- claude.ai work goes to stable Chrome, profile `<state>/chrome-claude`, debug port 9222.
- It is opened as `--app=` windows, which have no tab strip and no omnibox.
- One profile signed in once, many windows. Each session window is another `--app` window on the same running process, so it inherits the cookies and never signs in again.
- The Chrome for Testing pool stays for everything else, and stays off claude.ai.

Chrome's singleton lock has a catch. `--window-size` and `--window-position` are dropped for a second window on a live profile, so placement happens afterward through our desk tool rather than at launch.

Signing in also stopped needing a person. A mail rule on anthropic.com senders forwards the magic link, and the agent completes the login itself.

There was a related bug in how we tell whose window is whose. [Ownership was decided from the Chrome binary](/blog/window-addressing-by-identity/), but the agent's main Chrome runs the same binary as ours against a different profile. Every window it owned was filed as ours, and no automation would touch it. It now resolves on the profile.

The pool was built for isolation and disposable state, and that is exactly what an elevated-auth check punishes. A browser that forgets who it is on purpose can't hold an identity that has to be remembered.

If an automated browser gets bounced right after a successful sign-in, check whether the page needs a persistent device identity before assuming bot detection. Keep the logins that need one in a single long-lived profile, and keep disposable browser pools away from them.
