Home | Send Feedback

Password auto login with the Credential Management API

Published: June 13, 2019  •  java, javascript, spring, ionic4

The Credential Management API is a browser API that allows a JavaScript application to interact with the integrated password manager.

With the Credential Management API, an application can store and retrieve password and federated login credentials and also plays a role in the WebAuthn standard, where it stores public keys.

This blog post focuses on the password part of the interface and looks at how the API can support the traditional username/password login flow.

The following example is going to use the PasswordCredential object and calls the store() and get() methods to store password credentials into the password manager and to retrieve them.

This part of the Credential Management API is, at the time of writing (June 2019), only implemented in Chrome. Check out caniuse.com website for the current support: https://caniuse.com/#feat=credential-management

Demo application

In this blog post, I show you an example with a Spring Boot back end and an Ionic front end. The Spring Boot application uses Spring Security to implement a traditional session cookie based form login process. I won't go much further into detail about the back end because the Credential Management API is a client-side API and works with any back end technology.

You find the source code for the Spring Boot application on GitHub:
https://github.com/ralscha/blog2019/tree/master/credential/server


The Ionic application consists of two pages, a home page, that users only see when they are logged in and a login page. The home page is protected with a CanActivate Angular route guard that checks if a user is logged in and if not redirects to the login page.

demo app login demo app home

Here the route configuration of the demo application.

const routes: Routes = [
  {path: '', redirectTo: 'home', pathMatch: 'full'},
  {path: 'home', canActivate: [AuthGuard], loadChildren: () => import('./home/home.module').then(m => m.HomePageModule)},
  {path: 'login', component: LoginPage}
];

app-routing.module.ts

On the login form, we add the recommended autocomplete attribute on the input fields to help the integrated password managers to retrieve the correct fields.

      <ion-item>
        <ion-label position="stacked">Username</ion-label>
        <ion-input autocomplete="username" name="username" ngModel required type="text"></ion-input>
      </ion-item>

      <ion-item>
        <ion-label position="stacked">Password</ion-label>
        <ion-input autocomplete="password" name="password" ngModel required type="password"></ion-input>
      </ion-item>

login.page.html

Because only Chrome has an implementation for PasswordCredential, we need to treat this feature as a progressive enhancement and add a feature detection check before we access the API. This way the application works in any browser, but only on Chrome we are going to see the auto sign-in process.

if ((window as any).PasswordCredential) {

Chrome password settings

In Chrome, we have two settings that control the behavior of the integrated password manager. Open the settings page with chrome://settings/passwords.

chrome password settings

The first option enables or disables the password manager, and the second option enables auto sign-in. We are going to see how these options, especially the second one, affect the behavior of our demo application.

Without Credential Management API

For the first test, we enable the password manager and disable the auto sign-in option (according to the screenshot above). Additionally, we don't access the Credential Management API in the application.

When we log in, Chrome's password manager recognizes the login request and opens a dialog where it offers to save the credentials.

chrome password login chrome password save password

If the user saves username and password and then opens the login page later, Chrome auto-fills the fields with the stored credentials. The user only has to click or tap on Login and is logged in.

chrome password auto fill

The password manager also supports multiple accounts per site. In that case, the user sees the following dialog when he focuses the username field.

chrome password multiple accounts

Credential Management API: Store Credentials

Next, we add code to our Ionic application that stores the password credential after the login request was successfully approved by the server.

  private async storePassword(username: string, password: string): Promise<any> {
    if (!(window as any).PasswordCredential) {
      return Promise.resolve();
    }

    const cred = new (window as any).PasswordCredential({
      id: username,
      password,
      name: username
    });
    return (navigator as any).credentials.store(cred);
  }

auth.service.ts

Important here that we first add a feature detection check, so the application also runs on browsers that do not support this feature. The application then creates a PasswordCredential object and stores it with navigator.credentials.store into the password manager.

When we run the application, we see the exact behavior as before. The browser displays the Save Password dialog.

chrome password save password

Even with the explicit call to navigator.credentials.store the user is still in charge of the workflow. He can deny the request or allow it. There is no option to store the credential silently.

The benefit of storing the credentials via JavaScript is that the browser no longer has to guess which are the correct fields (username and password) for logging in to this application.

Credential Management API: Retrieve Credentials

As mentioned at the beginning we can not only store credentials we can also retrieve them from JavaScript with the navigator.credentials.get method.

With this capability, we can implement an auto sign-in solution that skips the login page when the password manager contains stored credentials for this site.

A good place for this to implement is the router guard. When the user navigates to the home page, Angular first executes the canActivate method of the guard.

The application first checks if the user is already logged in.

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
    if (this.authService.isLoggedIn()) {
      return true;
    }

    return this.authService.isAuthenticated().pipe(
      mergeMap(success => {
        if (success) {
          return of(true);
        }
        return this.tryAutoSignIn();
      }),
      map(success => {
        if (success) {
          return true;
        }
        return this.router.parseUrl('/login');
      })
    );
  }

auth.guard.ts

If not the code tries to fetch the password credentials from the password manager with navigator.credentials.get. If the method returns a credential, the application sends a login request to the server.

  private tryAutoSignIn(): Observable<boolean> {
    if (!(window as any).PasswordCredential) {
      return of(false);
    }

    return fromPromise((navigator as any).credentials.get({password: true}))
      .pipe(
        mergeMap(cred => {
            if (cred) {
              const c = cred as any;
              return this.authService.login(c.name, c.password);
            }
            return of(false);
          }
        )
      );
  }

auth.guard.ts

If you run this code and navigate to the home page (/ or /#/home) the Chrome browser displays the following dialog when our code calls the navigator.credentials.get method and there are credentials stored.

chrome password save password

The method returns the credential if the user clicks on Sign in and our application sends a login request to the server. If that request is successful, the application displays the home page.

If the user cancels the "Sign in as" dialog, the get method returns null, and the program displays the login page. The same happens when the browser does not support the PasswordCredential API.

Auto Login

This was already an improvement because we can skip the login page if credentials are stored in the browser, but the user still has to click on the Sign in button.

To make this even more convenient, the user can enable the second option (Auto Sign-in) on the password settings page.

chrome password auto sign-in

The call to navigator.credentials.get now no longer displays the "Sign in as" dialog and instead immediately returns either the stored credentials or null.

The browser displays the following dialog to inform the user that a sign-in occurred. chrome password auto sign-in

Note that when multiple accounts are stored for a site, the browser displays the "Sign in as" dialog, even when the "Auto Sign-in" feature is enabled.

chrome password multiple accounts


This concludes this tutorial about integrating the Credential Management API with a traditional username/password login flow.

See also the following two articles for more information about the API:


The source code for the demo application is hosted on GitHub:
https://github.com/ralscha/blog2019/tree/master/credential