Every profile carries its own authenticator. A passkey enrolled inside a profile is captured, kept on your disk, and replayed the next time that identity signs in - next process, next week, or on another machine.
Sites are switching sign-in to passkeys by default, and a passkey is deliberately bound to the authenticator that created it. On an ordinary machine that authenticator is the machine, which is fine for one personal account and wrong for everything else you do here.
The platform authenticator is shared by every profile on the computer. Register a second account on the same site and you are asking one device to hold two identities that were never supposed to meet.
Touch ID and Windows Hello want a human finger. An agent that hits a passkey prompt stops there, which is how a script that logged in fine last month quietly becomes a script that cannot log in at all.
Change machine and the credential stays behind, because that is exactly what hardware binding is for. Your cookies moved. Your passkey did not, and the account is now unreachable from the new machine.
// Nothing to enable. Capture and replay are on by default. const { browser, page } = await ab.launch({ profile: "seller-04" }) // Register a passkey on the site, by hand or with the agent. // It lands in <profile>/passkeys.json, not in the OS keychain. await page.goto("https://webauthn.io") // Next week, next process, next machine: same profile, still signed in. const { page: later } = await ab.launch({ profile: "seller-04" }) await later.getByRole("button", { name: "Sign in with a passkey" }).click()
// Per profile, if you would rather approve each enrolment yourself. await ab.launch({ profile: "seller-04", webauthnCapture: false }) # Python, same profile format, same store browser = await launch_async(profile="seller-04", webauthn_capture=False)
The profile is the device. Its authenticator answers the site's WebAuthn call inside the browser, and the credential is written to a file in that profile rather than to the computer's keychain.
The test we run against this is deliberately brutal. Register a passkey on webauthn.io in a profile, close the browser, delete the entire local profile directory, then restore the same profile on a clean directory and sign in using nothing but that passkey. It is part of the suite for both the Node and Python SDKs, so it has to keep passing to ship. Repeat it yourself on the free tier: the walkthrough is here.
Each profile enrols its own credential, so accounts on the same site never share an authenticator. The site sees separate devices because, in every way it can check, they are.
An agent registering today and returning next week needs the same credential to still be there. Randomising per launch is the opposite of what a long-lived identity needs. More on agent setups.
Export the profile and the person who imports it can sign in, without a password reset, an SMS code, or a shared phone. The credential is in the file they received.
Google can bind a session to a key held in the TPM or Secure Enclave, and that key is not exportable by design. Copying the profile does not copy it, so we disable that mechanism rather than let it half-work. What crosses the network, and what does not.
This stores WebAuthn credentials for the profile that created them. It does not sync your passwords, and it does not import passkeys out of iCloud Keychain or a phone.
Staying signed in is not the same as being trusted. A burnt account, a bad proxy or robotic behaviour still gets flagged, and nothing on this page changes that.
In a file inside the profile directory, next to that profile's cookies and storage. It is not written to the macOS keychain, Windows Hello or a phone, which is what makes it belong to the identity rather than to the machine. Export the profile and the passkey goes with it.
Yes, and that is the point. Each profile has its own authenticator, so ten profiles are ten separate devices as far as the site is concerned. A platform authenticator on a normal machine is one device shared by every account, which is why the second account is usually where this breaks.
It sees a platform authenticator and gets a valid WebAuthn assertion. What it cannot do is read a serial number that identifies our software, because there is nothing vendor-specific in the credential. Nobody should promise more than that: WebAuthn attestation is a live area and any site that demands hardware attestation from a real security key is asking for something no software authenticator can produce.
With cloud sync on for that profile, the passkey store travels with it and the account signs in on the other machine. With sync off, nothing leaves your disk, and you move the identity yourself with a profile export. Both paths carry the same file.
Passkeys, yes. Google also runs device-bound sessions whose private key sits in the TPM or Secure Enclave and is not exportable by design, so that part cannot be moved by us or anyone else. We turn that mechanism off rather than pretend the copy works. It is described on the security page.
No. The agent clicks the same button a person clicks. There is no separate passkey API to call, because the credential is answered inside the browser, below the automation layer.
Unlimited local profiles on the free tier, each with its own authenticator. No credit card.