Signing In With Keys, Not Secrets

Public and private key pairs let a user or an agent prove who they are without ever sending a secret across the wire. Here is why that matters, and where it gets genuinely hard.

Part 1 of 2 · The concept and the human problem

The idea in one paragraph

In a key-pair scheme, every participant holds two matching values: a private key that never leaves their device, and a public key that they hand out freely. Anything signed by the private key can be verified by the public key, and only by it. So instead of a client proving itself by presenting a secret — a password, an API token, a long string buried in a URL — it proves itself by signing a one-time challenge. The secret stays put. The server only ever sees a signature, which is useless to an attacker who copies it.

Why bearer strings are the thing to leave behind

A great many systems still authenticate with what cryptographers call a bearer secret: whoever bears the string has access. An API key in a header, a session token, or a hard-to-guess identifier embedded directly in an endpoint like /api/get/<long-random-string> all share the same weakness. The credential travels on every request. It lands in server logs, in browser history, in referrer headers, in proxy caches. Copy the string and you are the user, indefinitely, with nothing to revoke short of rotating the secret for everyone.

Signature-based auth removes the thing worth stealing. The private key is used to sign, but is never transmitted, so there is nothing on the wire to capture and replay.

This is not exotic — the enterprise already runs on it

Key-pair signing is one of the most battle-tested ideas in computing. A few places it is quietly doing its job every day:

The point of the list is reassurance: adopting key-pair auth is not inventing something clever and fragile. It is joining a well-trodden path.

The hard part: ferrying keys between machines

Here is where honesty is required. The cryptography is the easy half. The difficult half is key management — specifically, what a human being experiences.

A private key generated in a browser lives in that browser. On that one machine it is effortless and invisible: no password to type, it simply works. But the moment the same person opens a second browser, or buys a new laptop, that key is not there — and to the server they are a total stranger. That wall is the entire user-experience problem in one sentence.

The realistic ways to cross it, from clunkiest to smoothest:

  1. Manual export and import. Show the user their key as a string or file; they save it and paste it into the second browser. Maximally private — the key touches nothing but their own devices — but awkward for non-technical people.
  2. Password-wrapped backup. Encrypt the private key with a passphrase and store the encrypted blob on the server. Any new browser logs in with the passphrase, pulls the blob, and decrypts locally. Feels like a normal password; the server never sees the raw key.
  3. Email magic link. Register with an email; to add a device, the user clicks a short-lived, single-use link that lets the new browser mint its own fresh keypair and register its public key. Email only ever carries a temporary ticket — never the private key itself.
  4. Passkeys. Hand the whole problem to the platform. The operating system generates, stores, and syncs the keypair through iCloud Keychain, a Google account, or a password manager; the user just uses Face ID. Same signing mechanic underneath.
The trap to avoid: emailing the private key itself inside a link. The instant the key rides in an email, it lives forever in an inbox, on a mail provider's servers, and in click logs — you have simply recreated the bearer-secret problem with extra steps. Mail a temporary login ticket, never the key.

Agents make this easy — they have no feelings about clunkiness

Everything above is a human problem. Humans forget passphrases, switch devices, and resent friction. An automated agent has none of these traits. Hand it a private key in a config file or a secrets vault and it is perfectly content — it will never sigh at exporting a string, never lose its laptop, never demand a nicer login screen.

This is exactly why agent-first platforms lean into raw keys. Give each agent its own keypair and you get something better than convenience: a durable, portable identity. "Knows the string" only ever means "someone who knows the string." A keypair means "specifically this agent" — and, if you want it, "acting on behalf of this specific human." The identity travels with the agent across systems, and access can be granted or revoked one key at a time.

The pragmatic split: for agents, use raw keypairs — simple and robust. For humans, use email magic links or passkeys to hide the key-management problem, with a manual export/import path for anyone who would rather not involve email at all.

Continue to Part 2 → A working FastAPI + browser login