Simple sign-in and registration forms are the goal, and saving credentials from them means returning users don't have to sign in again. The flow has five steps: mark up the form with autocomplete, stop it from submitting, authenticate with a request, store the credential, then update the UI.
Markup first: autocomplete
Start by checking that the form carries autocomplete attributes. They let the Credential Management API locate the id and password fields and build a credential object from them. Browsers that don't implement the API still read the attributes for their semantics. Jason Grigsby's article on autofill covers the background.
<form id="signup" method="post">
<input name="email" type="text" autocomplete="username email" />
<input name="display-name" type="text" autocomplete="name" />
<input name="password" type="password" autocomplete="new-password" />
<input type="submit" value="Sign Up!" />
</form>
Blocking the submit and authenticating
Handle the submit button so the form never actually submits, since a real submission triggers a page transition that discards the in-flight credential check. Keep the credential values in memory while verifying them:
var f = document.querySelector('#signup');
f.addEventListener('submit', e => {
e.preventDefault();
The values go to your server over AJAX. Your endpoint—new or repurposed—should answer with HTTP 200 or 401 so the browser can tell whether sign-up, sign-in, or password change succeeded.
// Try sign-in with AJAX
fetch('/signin', {
method: 'POST',
body: new FormData(e.target),
credentials: 'include',
});
Persisting the credential
Feature-detect the API, build a PasswordCredential passing the form element as the argument, then call navigator.credentials.store(). If the API isn't there, just pass the profile on to the next step. The constructor can be used synchronously or asynchronously.
if (window.PasswordCredential) {
var c = new PasswordCredential(e.target);
return navigator.credentials.store(c);
} else {
return Promise.resolve(profile);
}
if (window.PasswordCredential) {
var c = await navigator.credentials.create({password: e.target});
return navigator.credentials.store(c);
} else {
return Promise.resolve(profile);
}
Only store after the request has succeeded; persisting credentials from a failed request confuses returning users. In Chrome, a notification appears once credentials are available, offering to save a credential or a federation provider.
UI and further reading
When the request checked out, either render the profile information or move to the personalized page.
}).then(profile => {
if (profile) {
updateUI(profile);
}
}).catch(error => {
showError('Sign-in Failed');
});
});
Browser support, from the MDN sources: PasswordCredential is at version 51 in Chrome and 79 in Edge, with no support in Firefox or Safari, while navigator.credentials.store() is at 51 in Chrome, 79 in Edge, 60 in Firefox, and 13 in Safari.



