· deepdives · 6 min read
Beyond Passwords: A Deep Dive into Credential Management API Best Practices
A practical, security-first guide for web developers to move beyond passwords using the Credential Management API and WebAuthn. Learn secure patterns, integration tips, migration strategies, and server-side considerations to deliver passwordless or hybrid auth that improves security and UX.

Outcome-first introduction
By the end of this post you’ll know how to reduce your reliance on passwords, implement credential management correctly, and choose the right mix of PasswordCredential, FederatedCredential and PublicKeyCredential (WebAuthn) for your product - all while avoiding common security and UX pitfalls. Read on to make authentication both safer and simpler for your users.
Why passwords are still a liability (and what to aim for)
Passwords are familiar. They are also fragile. Users reuse them across sites. They choose weak values. They fall victim to phishing and database leaks. Short-term mitigations like complexity rules and CAPTCHAs increase friction but don’t solve the root cause.
What to aim for instead:
- Remove secrets that are easy to phish (passwords) where possible.
- Prefer cryptographic credentials bound to a device or user presence (passkeys/WebAuthn).
- Provide a clear fallback path (e.g., federated login or password fallback) to avoid user lockout.
- Make the authentication flow both secure and convenient.
The Credential Management API: what it is and why it helps
The Credential Management API exposes a standard browser interface to store and retrieve credentials. It unifies three credential types:
- PasswordCredential - username/password tuples stored by the browser.
- FederatedCredential - tokens from identity providers (Google, Facebook, etc.).
- PublicKeyCredential - WebAuthn passkeys and hardware-backed credentials.
The API enables streamlined sign-in flows and credential mediation (account chooser, silent sign-in). It is a progressive enhancement: feature-detect and fall back when unsupported. See MDN for the API surface: https://developer.mozilla.org/en-US/docs/Web/API/Credential_Management_API
Quick feature-detection and patterns
Always check for the APIs before using them.
if ('credentials' in navigator) {
// safe to call navigator.credentials.get()/store()
}
if (window.PublicKeyCredential) {
// WebAuthn support available
}Use progressive enhancement. Do not rely on client-only logic for security decisions; the server must always validate.
Best practices by credential type
PasswordCredential (legacy, still useful as a fallback)
- Use PasswordCredential for improving traditional password sign-in UX (auto-fill, account chooser). Example:
if (navigator.credentials && window.PasswordCredential) {
const cred = new PasswordCredential({
id: email, // typically the user's ID/email
name: displayName,
password: userPassword,
iconURL: userIcon,
});
await navigator.credentials.store(cred);
}- Important: PasswordCredential support is inconsistent across browsers. Treat it as an enhancement, not the only plan.
- Do not store long-term secrets in client-side storage yourself. Let the browser manage credentials.
- Use
navigator.credentials.preventSilentAccess()on sign-out to stop automatic re-sign-in.
FederatedCredential (federated sign-in)
- Use FederatedCredential for OAuth/OIDC sign-in flows to integrate with identity providers.
- Use federated sign-in to reduce friction, but avoid using it as the only security mechanism (account linking and recovery are necessary).
- Keep your OAuth flows PKCE-enabled and validate tokens on the server.
PublicKeyCredential / WebAuthn (passkeys & strong authentication)
- Use PublicKeyCredential for passwordless or strong multi-factor authentication. It’s the current best path for phishing-resistant authentication.
- Registration is done client-side with
navigator.credentials.create({ publicKey }). The server must generate a challenge and verify attestation.
Example (client-side):
// server() returns challenge and RP info
const creationOptions = await fetch('/webauthn/registerOptions').then(r =>
r.json()
);
creationOptions.challenge = base64ToArrayBuffer(creationOptions.challenge);
creationOptions.user.id = base64ToArrayBuffer(creationOptions.user.id);
const credential = await navigator.credentials.create({
publicKey: creationOptions,
});
// send credential.response to server to finish registrationServer-side verification steps (overview):
- Validate the challenge and origin.
- Verify attestation signatures and certificate chains (for attestation types that include them).
- Store the public key and counter for the credential.
- Enforce
userVerificationandattestationpolicies according to your risk model.
Authoritative spec: https://www.w3.org/TR/webauthn-2/ and a practical guide: https://webauthn.guide/
Credential mediation: quiet sign-in vs. user control
Mediation determines how the browser surfaces credentials:
silent- the browser will try to get credentials silently (good for single-click re-auth).optional- browser can show UI but not force a prompt.required- browser must show an account chooser.
Example:
const cred = await navigator.credentials.get({
password: true,
federated: { providers: ['https://accounts.google.com'] },
mediation: 'optional',
});Best practice: Use required for account selection on shared devices and silent for background reauthentication where you’ve explicitly requested it. Always allow the user to pick an account - never silently log a user into a different account without confirmation unless you have explicit, tested UX that indicates otherwise.
UX recommendations - reduce friction, avoid surprises
- Offer a clear path to register a passkey during or immediately after password sign-in (progressive migration).
- Present account chooser UI when multiple credentials are available.
- Expose an explicit “Use passkey” or “Use password” option; don’t auto-upgrade users without consent.
- For mobile and cross-device flows, provide QR-code or email link transfer flows to provision passkeys on another device.
- Provide a recover/backup plan: email+password fallback, account recovery flows, or device attestation policies - because users will lose devices.
Server-side security checklist
- Always verify WebAuthn challenges and attestation server-side. Don’t trust client-side signals alone.
- Force HTTPS and use strict CSP to reduce injection risks that could steal credentials.
- Use short-lived session tokens and refresh tokens with rotation.
- Keep a revocation list for credentials and support device management (list and revoke registered authenticators).
- Log important events (registration, authentication, revocation) and monitor for anomalies.
Handling migration from passwords to passkeys
A safe migration path increases adoption and reduces abandonment:
- Offer passkey registration after a successful password sign-in.
- Allow users to sign in with either method while you validate passkeys server-side.
- Encourage passkey use (e.g., faster login banner) but keep password fallback for recovery.
- After a probation period, consider nudging heavy users to deprecate passwords but retain them for recovery policies.
Common pitfalls and how to avoid them
- Pitfall: Relying on client-only checks. Fix: Validate everything server-side.
- Pitfall: Silent sign-in that surprises users. Fix: Use
mediation: 'required'on shared contexts. - Pitfall: Not handling unsupported browsers. Fix: Feature detect and use clear fallbacks (email link, OTP, OAuth).
- Pitfall: Poor revocation UX. Fix: Provide a device page with clear revoke and recovery options.
Privacy and cross-origin considerations
- Credential Management API is origin-scoped. Only the origin that stored a credential can retrieve it.
- Avoid leaking user enumeration through verbose error messages on auth endpoints. Use consistent timing and messages where appropriate.
- If you use third-party identity providers, read their privacy and scope rules carefully and request the minimum scopes required.
Example end-to-end flow (high level)
- User signs up with email + password or OAuth.
- Offer passkey registration: server issues WebAuthn challenge and client calls
navigator.credentials.create. - Server verifies attestation and persists public key, sign-in preferences, and a credential ID.
- On subsequent sign-in, the client calls
navigator.credentials.getwith the challenge; server validates signature and establishes a session token. - User can manage or revoke credentials in account settings;
navigator.credentials.preventSilentAccess()is used on sign-out to avoid unexpected re-sign-ins.
Security checklist (quick reference)
- Enforce HTTPS and HSTS.
- Use CSP and cookie flags (HttpOnly, Secure, SameSite=strict where possible).
- Validate WebAuthn challenges & origins server-side.
- Use PKCE for OAuth/OIDC flows and validate tokens server-side.
- Provide device management for credential revocation.
- Log and monitor authentication events.
Resources and references
- Credential Management API (MDN): https://developer.mozilla.org/en-US/docs/Web/API/Credential_Management_API
- WebAuthn spec (W3C): https://www.w3.org/TR/webauthn-2/
- WebAuthn Guide (practical): https://webauthn.guide/
- Google Passkeys overview: https://developers.google.com/identity/passkeys
Conclusion
Passwords will remain in the ecosystem for a while, but you don’t have to accept their risks as inevitable. Implement the Credential Management API as a progressive enhancement, prioritize WebAuthn/passkeys where feasible, offer thoughtful fallbacks, and validate everything on the server. Do this and you’ll deliver authentication that’s both stronger and more pleasant - exactly what modern users expect.



