How-to enable the built-in password saving prompt in Chrome with Vue.js 2, BootstrapVue, and axios

3.7k views Asked by At

I’m turning mad, because I can’t make the Chrome Password Manager ask for password saving with a form. Let’s say that Firefox saves both username/ e-mail and password without issues: Chrome, on the other hand, ignores every change I've made.

I already know that Google published the best practices for this achievement, but I can’t use the Fetch API to login and I wasn’t able to adapt the suggested code to axios, I got just an error message, saying that I need to store credentials in either a passwordCredentialData or HTMLFormElement, trying to use the PasswordCredential constructor (no matter how I pass those credentials).

Anyway, the form itself should support the browser’s built-in functionality. Here’s a sample of the output code:

<form>
  <fieldset>
    <input id="email" name="email" type="email" required="required" autocomplete="username email">
    <input id="password" name="password" type="password" required="required" autocomplete="current-password">
  </fieldset>
  <button type="submit"></button>
</form>

This should have been enough, but it’s a form generated by Vue.js and BootstrapVue. I’m already aware of the known issues with AJAX. Also, I tried adding action="/login" and method="post" in the <form> element tag and it hasn’t changed anything. Then, I tried with new-password – instead of current-password – too… nothing has changed.

Of course, being generated by BootstrapVue, the sources are a bit different.

<b-form @submit.prevent="handleLogin">
  <b-form-group>
    <b-form-input autocomplete="username email" id="email" name="email" required type="email" v-model="form.email"></b-form-input>
    <b-form-input autocomplete="current-password" id="password" name="password" required type="password" v-model="form.password"></b-form-input>
  </b-form-group>
  <b-button type="submit"></b-button>
</b-form>

I removed classes and other pieces of code not involved in the issue, such as placeholders and labels, for better reading. I called an onsubmit event as described here.

I learnt that Google activates the Chrome Password Manager after a successful redirect (a Vue.js route redirection, in this case) — so the relative logic is crucial. I tried adding { withCredentials: true } to the axios request properties, but as I said it fails to create a new PasswordCredential constructor, because of the data format. It’d be ideal to use Vue.js form.email and form.password pre-defined models, although it also fails with a dedicated FormData object.

async handleLogin() {
  await axios
    .post("/auth", {
      email: this.form.email,
      password: this.form.password
    },
    {
      withCredentials: true
    })
      .then({
        ...
      })
      .catch({
        ...
      });
}

Above, the first lines of the method are used to handle the login. I think that this could be just a starting point, since Google Developers show how-to store credentials with the Fetch API and the PasswordCredential constructor. I browsed the SO archive for weeks, but I still can’t go any further; making a syncronous call doesn’t solve the issue, if you’re minding. What am I doing wrong?

EDIT • Is it ever possible that Google Password Manager doesn’t work just because I’m on an unsecure area (a local domain without or with an unsigned SSL certificate)?

1

There are 1 answers

0
Federico Moretti On BEST ANSWER

AFAIK (reading this thread in Google Help Center) although the code below should work, it actually doesn’t if the related domain hasn’t a valid SSL certificate.

async handleLogin() {
  await axios
    .post("/auth", {
      email: this.form.email,
      password: this.form.password
    },
    {
      withCredentials: true
    })
      .then({
        ...
      })
      .then(() => {
        if (window.PasswordCredential) {
          const passwordCredential = new PasswordCredential({ id: this.form.email, password: this.form.password });
          navigator.credentials.store(passwordCredential);
        }
        ...
      })  
      .catch({
        ...
      });
}

This has been inspired by a newer version of the official documentation and should work for those who provide a valid SSL certificate only. Right now, there isn’t a way to overcome this issue as of #142818.

EDIT • If your developing site or webapp is under localhost, then you may want to enable “Allow invalid certificates for resources loaded from localhost.” from chrome://flags/#allow-insecure-localhost.

EDIT • Unfortunately, enabling chrome://flags/#unsafely-treat-insecure-origin-as-secure for custom domains doesn’t change anything (and makes Chrome even more unstable).