Credentials
The Credential Management API allows authorized Web applications to store and request user credentials (like login and password or federated login data) programmatically on behalf of the user. The API offers a replacement for browser built-in or 3rd-party password stores which allows the Web application to instrument when and how the credentials are stored and read, for example to offer automatic sign-in capability.
When retrieving the previously stored credential, the Web application may decide if the user mediation is expected. When mediation
flag is set to silent
, the credential will only be resolved if the user had previously stored the single credential for this application. With optional
option set, the UI to choose the credential will appear unless there's a single credential stored. Finally, with required
option, the UI will always be shown, regardless of the previously stored credentials existence.
As of early 2020, there is also a proposal for the API to address delivering one-time passwords to be used in multiple factor authentication schemes. The earlier version of this API addition was experimentally implemented in Chrome 78-80 for Android within navigator.sms
interface. The API relies on the specific message content convention – the message is expected to contain the requesting app's URL. Right now it only defines SMS as a message transport.
API glimpse
credential = new PasswordCredential(form)
- Creates the credential object based on the username and password data detected in a HTML
<form>
element. credential = new PasswordCredential({id, password, name, iconURL})
- Creates the credential object manually based on the data provided.
credential = new FederatedCredential({id, name, iconURL, provider, protocol})
- Creates the credential object based on the federated login service specified with
provider
andprotocol
options. navigator.credentials.store(credential)
- Stores the credential provided for future access. Returns a
Promise
resolved when the credential is successfully persisted by the browser. navigator.credentials.get({mediation})
- Retrieves the previously stored credential from the browser, optionally with user mediation (UI). Returns a
Promise
resolved with fetched credential ornull
. navigator.credentials.preventSilentAccess()
- Ensures the user mediation is required on the next credential access request, effectively "logging out" the user.
Web OTP API (proposal)
navigator.credentials.get({otp: {transport: ['sms']}})
- Returns a
Promise
resolved with the one-time password (code) when the device receives the OTP SMS message containing the requesting URL and the code.
Live Demo
-
function storeCredential() { event.preventDefault(); if (!navigator.credentials) { alert('Credential Management API not supported'); return; } let credentialForm = document.getElementById('credential-form'); let credential = new PasswordCredential(credentialForm); navigator.credentials.store(credential) .then(() => log('Storing credential for <b>' + credential.id + '</b> (result cannot be checked by the website).')) .catch((err) => log('Error storing credentials: ' + err)); } function requestCredential() { if (!navigator.credentials) { alert('Credential Management API not supported'); return; } let mediationValue = document.getElementById('credential-form').mediation.value; navigator.credentials.get({password: true, mediation: mediationValue}) .then(credential => { let result = 'none'; if (credential) { result = credential.id + ', ' + credential.password.replace(/./g, '*'); } log('Credential read: <b>' + result + '</b>'); }) .catch((err) => log('Error reading credentials: ' + err)); } function preventSilentAccess() { if (!navigator.credentials) { alert('Credential Management API not supported'); return; } navigator.credentials.preventSilentAccess() .then(() => log('Silent access prevented (mediation will be required for next credentials.get() call).')) .catch((err) => log('Error preventing silent access: ' + err)); } function waitForSms() { if ('OTPCredential' in window) { log('Waiting for SMS. Try sending yourself a following message:\n\n' + '<pre>Your verification code is: 123ABC\n\n<br>' + '@whatwebcando.today #123ABC</pre>'); navigator.credentials.get({otp: {transport: ['sms']}}) .then((code) => log('Code received: ' + code)) .catch((error) => log('SMS receiving error: ' + error)); } else { alert('Web OTP API not supported'); } } function log(info) { var logTarget = document.getElementById('result'); var timeBadge = new Date().toTimeString().split(' ')[0]; var newInfo = document.createElement('p'); newInfo.innerHTML = '<span class="badge">' + timeBadge + '</span> ' + info; logTarget.appendChild(newInfo); }
-
<div class="columns"> <div class="column"> <form id="credential-form" onsubmit="storeCredential(event)"> <h2>Credentials Management API</h2> <p><b>Store your credentials:</b></p> <p> <label>login: <input type="text" name="username" required autocomplete="username"></label> <label>password: <input type="password" name="password" required autocomplete="current-password"></label> </p> <p><button type="submit">Store credential</button></p> <p class="user-mediation"> <b>User mediation:</b><br/> <label><input type="radio" name="mediation" value="silent"> silent</label> <label><input type="radio" name="mediation" value="optional" checked> optional</label> <label><input type="radio" name="mediation" value="required"> required</label> </p> <p><button type="button" onclick="requestCredential()">Request credential</button></p> <p><button type="button" onclick="preventSilentAccess()">Prevent silent access (logout)</button></p> <hr> <h2>Web OTP API</h2> <p><button type="button" onclick="waitForSms()">Wait for OTP SMS</button></p> </form> </div> <div class="column" id="result"></div> </div>