Skip to main content

“Passkeys are a trap. Do not use them” reached the front page of Hacker News this weekend with 528 points. The author’s objection is not really about cryptography, which he concedes is excellent. It is about control: you cannot easily find your passkeys, and the places where you are meant to manage them are buried somewhere inside an account settings page you have to go hunting for.

Half of that complaint has had a specification attached to it since January. The W3C Web Application Security Working Group publishes A Well-Known URL for Relying Party Passkey Endpoints, which lets any site hand a password manager a direct link to its passkey creation page and its passkey management page. A second specification, the related origins feature in WebAuthn Level 3, lets one passkey work across a company’s other domains. Both are a single static JSON file.

So we measured who actually serves them. Not the top of the web generally, where almost nobody has a login at all, but the specific population of sites that demonstrably ship passkeys today. On 12 October 2026 we probed 255 of them. Twelve serve the file in a state a conformant client can read.

TL;DR

  • Of 218 passkey-shipping domains, 27 return HTTP 200 for /.well-known/passkey-endpoints and only 12 do so conformantly. Two of the twelve are names you would recognise: Shopify and Uber.
  • Thirteen sites, including Amazon, PayPal, eBay, Adobe, Coinbase, Dropbox and Target, serve the file only behind an apex-to-www redirect. The specification says, in four words, “A redirect MUST not be returned.”
  • One site publishes a trailing comma. finom.co serves HTTP 200 and application/json, and no JSON parser will accept the body. luma.com wraps its related-origins object in an array, which WebAuthn says must throw.
  • The control probe mattered as much as the measurement. Twenty-four domains returned 200 for a path we invented, sixteen of them also for /.well-known/change-password.
  • passkey-endpoints is not in the IANA well-known URI registry at all, while webauthn was granted a permanent registration on 23 January 2026.

What the two files are supposed to do

The passkey endpoints draft is edited by Tim Cappalli of Okta and Matthew Miller of Cisco, and was published as a W3C Working Draft on 14 January 2026. The document is 8.6KB of Bikeshed source and the normative part is three sentences long. A relying party hosts a JSON document at https://<rp-id>/.well-known/passkey-endpoints. “A redirect MUST not be returned.” A successful response “MUST use the 200 OK HTTP status code and return a JSON object using the application/json content type.”

Inside the object, three members are defined and all three are explicitly OPTIONAL: enroll, a direct URL to the passkey creation page; manage, a direct URL to the passkey management page; and prfUsageDetails, a page explaining what else the site does with your passkey besides log you in.

The specification’s own rationale reads like a reply to the Hacker News post. On manage: “Credential management is often buried inside account settings, which can be difficult for users to find.” Google’s developer relations team asked Android developers to publish the file in October 2023, three years ago, precisely so that password managers could offer a “passkey upgrade available” button.

The second file, /.well-known/webauthn, solves a different problem: by default a passkey is bound to one registrable domain, and the related origins feature lets you publish an origins array to share one credential across several. The WebAuthn text here is stricter than most people realise. If the fetch fails, if the content type is not application/json, if the status after redirects is not 200, or if the body is not a valid JSON object with a string array at origins, the client must throw a SecurityError. There is no partial credit.

How we built the population

Probing the Tranco top million for passkey endpoints tells you very little, because the overwhelming majority of those hostnames are CDN edges and image domains with no account system at all. The honest denominator is sites that already ship passkeys.

passkeys.directory, run by Hanko, maintains exactly that list, and its Gatsby front end reads from a public Supabase table. We pulled all 4,603 rows. Filtering to approved, non-hidden entries gives 4,167 sites, of which 243 are flagged as supporting passkey sign-in and a further 12 as passkey-based multi-factor only. After normalising and de-duplicating hostnames that gives 255 domains.

For each domain we requested four paths: the two specification endpoints, /.well-known/change-password as a convention control, and /.well-known/reptilehaus-control-9f3a2c, a path we invented, as a soft-404 control. Any domain that returns 200 for a path nobody has ever published is a domain whose 200s mean nothing. Twenty-four did, including twitter.com, tiktok.com, dell.com, costco.ca and, with a certain irony, passkeys.guru and passage.1password.com. Sixteen of them were also returning 200 for the change-password path, so reading adoption straight off the status code would have inflated that figure by more than half. A further 13 were unreachable from our network, leaving a clean population of 218.

Finding 1: the file exists, the redirect eats it

Twenty-seven of the 218 return HTTP 200 for /.well-known/passkey-endpoints once redirects are followed. The other 191 do not: 146 plain 404s, 34 403s, and a scattering of 400s, 500s and one 204.

Thirteen of those 27 are reachable only because we followed a redirect:

Domain Apex response Redirects to
amazon.com 301 www.amazon.com
paypal.com 301 www.paypal.com
ebay.com 301 www.ebay.com
adobe.com 301 www.adobe.com
coinbase.com 302 www.coinbase.com
dropbox.com 301 www.dropbox.com
target.com 301 www.target.com
canva.com 301 www.canva.com
kayak.com 301 www.kayak.com
wealthsimple.com 301 www.wealthsimple.com
freetaxusa.com 301 www.freetaxusa.com
trimble.com 301 www.trimble.com
simply.com 301 www.simply.com

Every one of these is the apex-to-www canonicalisation that every CDN, every framework and every hosting platform does by default. It is the single most boring line of configuration on the internet, and it sits directly between a password manager and the file these teams went to the trouble of writing.

This is worth separating from ordinary non-adoption, because the two have opposite fixes. A site with no file has not got to it yet. A site with a file behind a redirect believes the job is done. Amazon wrote a valid JSON document, deployed it, and a conformant credential manager asking amazon.com gets a 301 and stops.

Finding 2: two of the files are not JSON

Of the 27 that answer 200, 25 parse as a JSON object. The two that do not are instructive.

kayak.com serves an HTML document. Its www host hands back the single-page application shell for any unmatched path, which is a soft 404 wearing a 200.

finom.co, a European business banking provider, serves this, with the correct status code and the correct content type:

{
    "enroll": "https://app.finom.co/settings/security",
    "manage": "https://app.finom.co/settings/security",
}

That trailing comma is not legal JSON. The file is four lines long, it has been deployed, it passes a human eyeball, and it fails a machine every single time.

Among the 25 that do parse, four get the content type wrong: PayPal and Coinbase send text/plain, Adobe sends no content type header at all, and Mercari sends application/octet-stream. Two publish an empty object, which the specification permits. Not one of the 218 publishes prfUsageDetails.

Apply all three requirements together, 200 without a redirect, application/json, a valid JSON object, and twelve sites pass: cardpointers.com, eduid.ch, heexy.org, id.moneyforward.com, id.tokyu.co.jp, moneybird.com, ope.ee, poblano.jp, ramp.com, shopify.com, techbookfest.org and uber.com.

Finding 3: related origins is rarer and quieter

Eight of the 218 answer 200 for /.well-known/webauthn. Seven publish a usable origins array: Amazon lists 103 origins across three registrable labels, Kayak 50, Notion nine, Shopify four.

The eighth is luma.com, which serves [{"origins":["https://lu.ma","https://luma.com"]}]. The object is wrapped in an array, and an array is not an object, so the algorithm throws. One bracket on each end is the difference between a passkey that works across lu.ma and luma.com and one that does not.

Finding 4: where “manage” actually sends you

We then followed every advertised enroll and manage URL: 44 probes, 27 of which returned 200. The honest limit here is that an unauthenticated probe cannot distinguish a broken link from a login wall, and most of the 403s are account pages behind a bot filter, exactly as they should be.

Two results survive that caveat. eduid.ch, the Swiss academic identity federation, advertises both endpoints and both resolve to a Shibboleth error page: HTTP 400 at handle-error?eventKey=stale. A credential manager sending a user to manage their passkey delivers them to a stale-flow error.

And fifteen of the 25 valid files point manage at the identical URL they point enroll at. Often that is fine, because one security settings page genuinely does both. PayPal is the exception worth naming: its manage value ends in /createPasskey, so the deep link added so users could manage existing credentials drops them into the creation flow.

What the control tells you about intent

Among the 218, 27 serve /.well-known/change-password. Only eight serve both it and the passkey file. Nineteen serve change-password and not the passkey file.

That nineteen is the interesting cell in the table. These are teams that know what a well-known URI is, have shipped one, and have a deployment path for static files at the root of their domain. They are not unaware of the convention. The passkey file simply has not reached anyone’s sprint.

The registry explains part of why. We pulled IANA’s well-known URI registry, 117 rows. webauthn is there with a permanent registration dated 23 January 2026. passkey-endpoints is not there at all; the draft says the registration “will be submitted to the IESG”.

What this means if you run a site with passkeys

Prior work exists and is worth citing honestly: a 2026 census of the Tranco top 100,000 found 12 sites exposing passkey-endpoints as of March 2025. What we have added is conformance, against a population where every site already ships the feature, and the result is that presence and function are not the same number.

The fix is a morning’s work, and it is four checks rather than one:

  1. Serve the file from the apex with no redirect. Test with curl and no -L flag; if you see a 301, your file does not exist as far as the specification is concerned.
  2. Assert the content type and parse the body in CI. Fetch the URL, assert status 200, assert application/json, assert the body parses, assert it is an object. Four of the 27 would fail the content-type line and two would fail the parse.
  3. Probe your own enroll and manage targets on a schedule. They are URLs into your account area, so they rot whenever someone restructures settings.
  4. If you run more than one domain, test the related-origins file against the actual algorithm. The failure mode is a silent SecurityError in somebody else’s browser.

There is a broader lesson here that has nothing to do with passkeys. Every one of these failures, the redirect, the trailing comma, the array wrapper, the text/plain, is a file that is right in the repository and wrong on the wire. That is the category of defect only first-hand probing from outside your own perimeter finds.

The Hacker News author is right that passkeys hand users less control than passwords did. He is also describing a gap the standards bodies have already specified a fix for, and that 206 of 218 passkey-shipping sites have not deployed. Those are two different problems, and only one of them needs a committee.

REPTILEHAUS builds and audits authentication and web infrastructure for clients across Europe. If you have shipped passkeys and nobody has verified what your domain actually returns to a credential manager, get in touch. Our earlier piece on why your web app should go passwordless covers the implementation side; this is the half that happens after launch.

Method note: all figures measured on 12 October 2026 from a single European vantage point, using a Chrome user-agent string and following HTTPS redirects only. Population from the passkeys.directory public dataset. Domains returning 200 for an invented control path were excluded.

📷 Photo by Yuriy Vertikov on Unsplash