Access browser stored passwords via Credentials API

Access browser stored passwords via Credentials API

The latest version of Chrome 51 (as of writing) supports the Credential Management API. It’s a proposal at the W3C that gives developers programmatic access to a browser’s credential manager and helps users sign in more easily.

Available on Chrome 51, Chrome Mobile 51, Safari Mobile 51, and Android WebView release 51

Browsers have for a long time stored your passwords, in chrome they offer them to you and highlight forms in an ugly yellow color.
As a user, you can identify visually if a site you are on has the ability to access these passwords by noticing the key symbol in the navigation bar;

Chrome showing you have stored passwords for this site

If you see this, then you will be able to access the form data the browser remembered in the past, but now, the website developers now also can access that same form data programmatically; with an exception to a password entered in the form that used the proper password HTML input;

<input type="password">

If they used the correct input, then as a user you would not have seen the password as you type. But like all passwords you trust they are not tracking your plain text password in some other way. Moving on.

Using PasswordCredential

Before continuing it's worth mentioning that you may only access the PasswordCredential via fetch and the endpoint for fetch must be on the same origin.

A basic login form;

<form action="/" method="POST" id="theForm">
  <label for="id">Name</label>
  <input type="text" name="id" id="id" value="">
  <label for="password">New Password</label>
  <input type="text" name="password" id="password" value="">
  <input type="submit">
</form>

And the JavaScript needed to validate with the server;

document.querySelector('#theForm').addEventListener("submit", function(e) {
  if (navigator.credentials) {
    var creds = new PasswordCredential(e.target);
    fetch(e.target.action, {
      method: "POST",
      credentials: creds
    }).then(function() {
      navigator.credentials.store(creds);
    });
  }
});

This so far shows a normal login form, nothing here is new in terms of functionality. The user gets a form, fills it in completely and sends their credentials to your server, which you would validate and log them in. Normally the user's browser would ask them if they wish to store the form data in the browser and if they chose yes the browser would fill in the form the next time they visited. However, the developer has not the ability to answer the question "would you like Chrome to save the form data" using navigator.credentials.store shown above. Neat!

The data accessible to you in the browser from the what the browser saved looks like this;

{
  "additionalData":null,
  "iconURL":"",
  "id":"person@gmail.com",
  "idName":"username",
  "name":"",
  "passwordName":"password",
  "type":"password"
}

No actual password can be read in the browser due to the PasswordCredential and fetch security functions, validation should still be performed on the server, always.

In addition, the website might need to store some more data in the browser without it being part of the form inputs, such as a SCRF token from the server. You can do this too! Using additionalData property as part of the PasswordCredential;

creds.additionalData = new FormData();
creds.additionalData.append("csrf", "[server token value goes here]")

Auto-login

By auto-login I mean the user won't need to interact with your site, but Chrome will ask for their permission;

Chrome asking the user for permission to use the stored password

navigator.credentials.get({ password: true }).then(function(credential) {
  if (!credential) {
    return;
  }
  if (credential.type == "password") {
    fetch("/", {
      credentials: credential,
      method: "POST"
    }).then(function (response) {
      // let the user know
    });
  }
});

This example will access the stored data in the browser form the first time the user filled out your form, sends it to your server for validation, and if that returns successful the website should consider the process of login successful.

Google or Facebook Federated Login

You can examine the type property of the credential object to see if it’s PasswordCredential type 'password' or FederatedCredential type 'federated'.

If the credential is a FederatedCredential, you can call the appropriate API using information it contains.

Here is a modified example of the above;

navigator.credentials.get({  
  password: true,
  federated: {
    providers: [
      'https://accounts.google.com',  
      'https://www.facebook.com'  
    ]  
  }  
}).then(function(cred) {
  // call the appropriate API
});

I won't go into using these providers APIs as they are not part of the Credentials API.

Logout

When a user signs out from your website, it’s your responsibility to ensure that the user will not be automatically signed back in. To ensure this, the Credential Management API provides a mechanism called mediation. You can enable mediation mode by calling navigator.credentials.requireUserMediation.

navigator.credentials.requireUserMediation();

Or in the navigator.credentials.get you can pass unmediated: false;

navigator.credentials.get({
  password: true,
  unmediated: false
}).then(function(cred) {
  // logged in this time, but will not auto-login
});

And there you have it, I hope this makes it's way into more browsers as it will not only pave the way to solve the password problem on the web but also drive usage and development of fetch.

Don't forget to share on Twitter below the comments if you liked this.
Follow me to stay updated with my newest content. Thank you.

Subscribe to Christopher D. Langton

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe