Evolution of login
Username/password forms
Stored credentials
Autofill
You can sync passwords across devices.
Federated identity providers
The Credential Management API
- Spec work started early 2015 [1]
- Championed by Mike West at Google [2]
-
Provides 2 key mechanisms
- Help the user authenticate by providing access to credentials
- Help the browser store credentials provided by the user
Assertion about an entity which enables a trust decision
Browser support
Demo!
Accessing stored credentials
<form method="post" action="/login" id="login-form">
<div>
<label for="username">Username:</label>
<input
type="text"
id="username"
name="username"
>
</div>
<div>
<label for="password">Password:</label>
<input
type="password"
id="password"
name="password"
>
</div>
<input type="submit" value="Login">
</form>
Signing in
const form = document.getElementById('login-form');
form.addEventListener('submit', (e) => {
e.preventDefault();
sendLoginRequest(new FormData(form));
});
Signing in
function sendLoginRequest(formData)
const fetchOpts = {
method: 'POST',
headers: {
Accept: 'application/json',
},
};
addCredentials(fetchOpts, formData);
makeRequest('/api/login', fetchOpts);
}
Signing in
function addCredentials(fetchOpts, formData) {
if (navigator.credentials) {
const credentials = new PasswordCredential({
id: formData.get('username'),
password: formData.get('password'),
});
credentials.additionalData = formData;
fetchOpts.credentials = credentials;
} else {
fetchOpts.body = formData;
}
return fetchOpts;
}
Signing in
function makeRequest(url, fetchOpts) {
return fetch(url, fetchOpts)
.then((res) => res.json())
.then((json) => validateResponse(json, formData))
.then((redirectUrl) => {
window.location = redirectUrl;
});
}
Storing valid credentials
// Validate the response from the auth service. Returns a URL to redirect
// the user to.
function validateResponse(res, credentials)
if (res.valid) {
// Logged in successfully. If the browser supports the Credential
// Management API we can attempt to save the provided login details.
if (navigator.credentials) {
return navigator.credentials.store(credentials)
.then(() => res.redirectUrl);
}
return res.redirectUrl;
}
throw new Error('Login failed.');
}
Accessing stored credentials
// If the browser supports the Credential Management API we can attempt to
// get a stored password credential. If no credential is stored, of if the
// call fails for any reason, the user can still log in like normal.
if (navigator.credentials) {
navigator.credentials.get({
password: true,
})
.then((credentials) => {
if (credentials) {
return sendLoginRequest(credentials);
}
return null;
});
}
Signing out
if (navigator.credentials) {
navigator.credentials.requireUserMediation()
.then(() => {
// Redirect to login page.
});
}
Security
- Page must be served from a secure origin (HTTPS)
- Credentials for other origins not available
- Stored passwords not exposed to JavaScript
- Stored passwords are encrypted
Questions?
Thank you!
@james_allardice
Building a better login (United Dev Conf, April 2017)
By James Allardice
Building a better login (United Dev Conf, April 2017)
- 1,274