Skip to main content
v2026.11,858 entries · CC-BY 4.0

WebAuthn: How Web Authentication Works (Registration and Sign-In)

How WebAuthn registration and sign-in work, what the server must verify, and how WebAuthn, passkeys, FIDO2 and CTAP relate, per W3C Level 3.

Written and maintained by CASRAI Editorial Board

Last updated

WebAuthn (Web Authentication) is a browser API, standardised by the W3C, that lets a website register and verify a user with a public-key credential instead of a password. The private key stays on the user’s authenticator (a built-in device or a security key), the server stores only the public key, and each sign-in signature is bound to the site’s origin, which is why WebAuthn is described as phishing resistant. This page walks through the registration and sign-in ceremonies in the order a developer or IT administrator implements them, lists what the server must verify, and maps the error cases you are most likely to hit.

It is written for research IT staff, developers of lab and repository portals, and security-minded administrators who need to understand how passkey and security-key sign-in actually works. Sources are the W3C Web Authentication Level 3 specification (W3C Recommendation dated 25 August 2026), the MDN Web Authentication API documentation and the FIDO Alliance passkeys page, all read on 7 November 2026.

What WebAuthn is used for in research

WebAuthn replaces or supplements password sign-in on any web application that holds access-controlled data. In a research setting that includes institutional single sign-on, data repositories, electronic lab notebook and LIMS portals, and grants or compliance systems. The specification describes the API as one for creating and using “strong, attested, scoped, public-key credentials”, where each credential is scoped to a single Relying Party (the website or service) and the user agent mediates every use. Authenticators must not act without user consent.

For campus federated login see the related guides on Shibboleth single sign-on and SAML authentication and InCommon identity federation; WebAuthn is the credential layer an identity provider can use to verify the person before it issues those assertions. For security obligations that attach to controlled research data, see CMMC compliance for research institutions, and for the underlying primitive see what is cryptography.

WebAuthn, passkey, FIDO2 and CTAP: what each term means

Term What it refers to Source
WebAuthn The W3C browser API (navigator.credentials.create() and navigator.credentials.get() with a publicKey option) that web applications call. W3C Web Authentication Level 3; MDN
CTAP The protocol between the browser or device and an external authenticator such as a USB security key. Cross-device sign-in uses the CTAP 2.2 hybrid transport, which relies on Bluetooth Low Energy proximity. FIDO Alliance
FIDO2 WebAuthn plus CTAP together. FIDO Alliance
Passkey A FIDO sign-in credential, written as a common noun. Passkeys may be synced across a user’s devices or device-bound. By definition a passkey is always a discoverable credential. FIDO Alliance; MDN
Discoverable credential (resident key) A credential for which the authenticator itself stores the private key material, the username and the RP ID, so the browser can list accounts without the server supplying credential IDs. MDN; W3C
Relying Party (RP) The website or service that registers and verifies credentials. Its RP ID scopes each credential. W3C
Authenticator A cryptographic entity, in hardware or software, that can register a user with a given Relying Party. It is either a platform authenticator (on the device) or a roaming authenticator (for example a USB security key). W3C

The FIDO Alliance notes that security keys have held device-bound passkeys since 2019, that biometrics stay on the device, and that some regulations do not yet list passkeys as multi-factor authentication. Check the exact wording of the control you must satisfy before treating a passkey as an MFA factor.

Install or access

There is nothing to install on the client: WebAuthn is a built-in browser API exposed through navigator.credentials. Two access conditions apply.

  • Secure context only. The API is available only over HTTPS (a secure context), in supporting browsers.
  • Permissions Policy. Embedded content is governed by the publickey-credentials-create and publickey-credentials-get directives, whose default allowlist is self. Where a policy forbids the method, the returned promise rejects with a NotAllowedError.

On the server you need code that generates a random challenge, parses the response and verifies it. You can write this yourself against the specification or use a library; see the libraries section below.

Step-by-step: registration and sign-in

Registration (creating a credential)

  1. The Relying Party server sends the user and Relying Party information and a challenge to the web app over a secure channel. The challenge must be a buffer of random bytes at least 16 bytes long.
  2. The web app calls navigator.credentials.create({ publicKey }). The options include the challenge, the rp (id and name), the user (id as opaque bytes, name, displayName), pubKeyCredParams (COSE algorithm identifiers such as ES256, -7), an optional timeout and an optional excludeCredentials list.
  3. After the authenticator obtains user consent, it generates a key pair and returns the public key and an optional signed attestation as a PublicKeyCredential.
  4. The web app forwards that object to the server.
  5. The server stores the public key against the user identity, after checking that the challenge matches the one it sent, that the origin is the expected origin, and that the signature and attestation use the correct certificate chain for the authenticator model.
const credential = await navigator.credentials.create({
  publicKey: {
    challenge: challengeFromServer,
    rp: { id: "example.org", name: "Example Repository" },
    user: { id: userIdBytes, name: "[email protected]", displayName: "A. User" },
    pubKeyCredParams: [{ type: "public-key", alg: -7 }]
  }
});

Sign-in (authentication)

  1. The server generates a new challenge and sends it to the browser, optionally with a list of acceptable credentials and hints about where to look (a built-in authenticator, or USB or BLE).
  2. The web app calls navigator.credentials.get({ publicKey }) with the challenge, an optional rpId, an optional allowCredentials list and a userVerification setting.
  3. If the authenticator holds a matching credential and the user consents, it signs the challenge and returns an assertion as a PublicKeyCredential.
  4. The web app forwards the assertion to the server.
  5. The server validates it and, if every check passes, the sign-in succeeds.
const assertion = await navigator.credentials.get({
  publicKey: {
    challenge: challengeFromServer,
    rpId: "example.org",
    allowCredentials: [{ type: "public-key", id: credentialIdBytes }],
    userVerification: "required"
  }
});

Passkey autofill (conditional mediation)

To offer passkeys in the browser’s autofill list, mark the username field with autocomplete="username webauthn", omit allowCredentials, and call navigator.credentials.get() with mediation: "conditional". This works with discoverable credentials. Feature-detect first with PublicKeyCredential.getClientCapabilities() and test its conditionalGet property. A conditional create call (mediation: "conditional" on create()) is not allowed from a cross-origin iframe.

Output and how to read it

Both calls resolve to a PublicKeyCredential. Its response property holds the interesting part: an AuthenticatorAttestationResponse after registration (the new public key and optional attestation) or an AuthenticatorAssertionResponse after sign-in (the signed assertion). Everything is sent to the server as bytes; the browser never decides whether the user is who they claim to be.

Server-side verification checklist

Ceremony What the server must verify Why
Registration The challenge equals the one it issued Ties the response to this attempt
Registration The origin is the expected origin Binds the credential to your site
Registration Signature and attestation use the correct certificate chain for the authenticator model Lets the Relying Party check authenticator provenance
Sign-in The stored public key validates the authenticator’s signature Proves possession of the private key
Sign-in The signed challenge matches the one the server generated Prevents replay of an old assertion
Sign-in The Relying Party ID is the one expected for this service Credentials are scoped to a single Relying Party

User verification matters when you want the sign-in to count as more than possession of the device. The specification’s sample code sets userVerification: "preferred" and notes this is the default. If the authenticator reports that user verification is not initialised, the user-verified flag must not be relied on as an authentication factor.

Troubleshooting

Symptom Documented cause What to check
navigator.credentials is unavailable or the call fails The API requires a secure context Serve the page over HTTPS
NotAllowedError inside an embedded frame A Permissions Policy forbids publickey-credentials-create or publickey-credentials-get; the default allowlist is self Review the Permissions-Policy header and the iframe allow attribute
NotAllowedError on conditional create Conditional create is not allowed from a cross-origin iframe Call it from a same-origin top-level page
Prompt disappears before the user responds Pending calls are cancelled if the browser window loses focus Keep the window focused and retry
Server rejects a valid-looking response Challenge, origin or RP ID differs from what the server expects Compare the values in the checklist above; make sure the rp.id you register with is the one you verify against
User verification flag cannot be trusted The authenticator’s user verification is not initialised Do not count the flag as an authentication factor; require verification or add another factor

Libraries for the server and browser

SimpleWebAuthn provides two complementary libraries, @simplewebauthn/server and @simplewebauthn/browser, intended to reduce the work of adding WebAuthn to a website. Check the project’s repository for its current licence and supported runtimes before adopting it. You can also implement the ceremonies directly against the browser API and the specification, as described above.

Frequently asked questions

Is WebAuthn the same as a passkey?

No. WebAuthn is the W3C API a site calls. A passkey is a FIDO sign-in credential built on that API, and by definition it is a discoverable credential. FIDO2 is the umbrella of WebAuthn plus CTAP.

What does WebAuthn store on the server?

Only the public key and the identity it is coupled to, together with the credential record the server needs for verification. The private key never leaves the authenticator.

Why is WebAuthn phishing resistant?

Each credential is scoped to one Relying Party and the signature is bound to the origin, so a lookalike site cannot obtain a valid assertion for your site.

Do users need to install anything?

No. It is a built-in browser API available over HTTPS. Users need an authenticator: a platform authenticator built into the device or a roaming security key.

Can a security key be a passkey?

Yes. The FIDO Alliance states that security keys have held device-bound passkeys since 2019.

Sources

Follow CASRAI

Research-administration guidance, standards updates and independent tool reviews.

Ask CASRAI · free to try

Ask about WebAuthn: How Web Authentication Works (Registration and Sign-In)

Ask your first 2 questions free below. Subscribers get 150 a day for $29 a month.

An AI assistant specialized in research administration. It cites the sources behind every answer, labels web answers and says when it can't answer.

Answers draw on CASRAI's guides and dictionary plus the federal and funder documents we index: Federal Register, Grants.gov, Regulations.gov and UKRI.

Works on this site and inside Claude, Cursor and the AI tools you already use.

Everything CASRAI publishes — this page, the dictionary, the guides and the news — stays free to read, with no account and no card.

Referenced across the research world

University of Cambridge logoColumbia University logoCrossref logoUniversity of Edinburgh logoHarvard University logoUniversity of Oxford logoPrinceton University logoStanford School of Medicine logoUniversity College London logoORCID logoUniversity of Cambridge logoColumbia University logoCrossref logoUniversity of Edinburgh logoHarvard University logoUniversity of Oxford logoPrinceton University logoStanford School of Medicine logoUniversity College London logoORCID logo
  • University of Cambridge logo
  • Columbia University logo
  • Crossref logo
  • University of Edinburgh logo
  • Harvard University logo
  • University of Oxford logo
  • Princeton University logo
  • Stanford School of Medicine logo
  • University College London logo
  • ORCID logo

View CASRAI adoption →