In this codelab, you'll learn how to implement the Credential Management API and bring automatic sign-in to an existing website built with a traditional architecture.

What you'll learn

What you'll need

Make sure your Chrome has "Offer to save your passwords" enabled.

How will you use this tutorial?

Read it through only Read it and complete the exercises

How would rate your experience with building web apps?

Novice Intermediate Proficient

While you can enable auto sign-in with the Credential Management API remotely from your laptop, this codelab uses Google Cloud Shell, a command line environment running in the Cloud. Google Cloud Shell is a Debian-based virtual machine that offers a persistent 5GB home directory and greatly enhances network performance and authentication. All you will need for this codelab is a browser (yes, it works on a Chromebook).

Set up a project in Cloud Console

If you don't already have a Google Account (Gmail or Google Apps), you must create one. Sign-in to Google Cloud Platform console (console.cloud.google.com) and create a new project:

Remember the project ID, a unique name across all Google Cloud projects.

Set up credential information for Google Sign-In

Open the API Manager from the menu to the left and choose "Credentials".

Then select "OAuth consent screen" tab, specify "Product name shown to users". This can be anything, but let's name it as "Credential Management Codelab" at this time. Then "Save".

Now let's activate the Cloud Shell. Simply click the button on the top right-hand side (it will take a few moments to provision and connect to the environment):

Press "Start Cloud Shell" when prompted. Once you have the Cloud Shell open, click on the preview button to open a browser window. Don't worry about the error message, this will be fixed.

We will use this browser window to preview the app. Take note of the URL in the browser, as you will use it later.

Go back to Credentials screen and select "Credentials" tab, click "Create credentials", and choose "OAuth client ID":

Select "Web application" type and enter the following in the form:

Once you have finished filling those fields, "Create" it, then download the JSON file with the credential information by clicking on the icon next to the entry on the right. It should be named something like client_secret_******.apps.googleusercontent.com.json. We'll use this JSON file's content in the next section.

Clone the repo

Come back to the Cloud Shell. We'll finally build the base code.

Firstly, git clone the repository:

$ git clone https://github.com/googlecodelabs/credential-management-api.git

Once the code is cloned, go into the directory and set up the environment.

$ cd credential-management-api
$ virtualenv env
$ source env/bin/activate
$ npm install

Create client_secrets.json

Finally, create a text file at root of the project with a name client_secrets.json and copy/paste the content of the JSON file you just downloaded named client_secret_******.apps.googleusercontent.com.json.

Move on

Phew, that was a bit of steps, but you are done with the set up!

Run the base code with following command:

$ dev_appserver.py working --host=0.0.0.0 --port=8080 --admin_port=8081

Click on the preview button to see the base code running.

Let's explore the website and examine what's happening and what we will be doing. To see current server side code, examine working/main.py.

Top page: /

You should see this page when you first open the website. You are signed out and there's a registration form. You will be redirected to /main if you are signed in.

Register endpoint: /register

By filling the form and pressing the "Register" button at the top page (/), a POST request will be sent to this endpoint, then redirected to the main page (/main) if successful or back to the top page (/) if failure.

Sign-in page: /signin

You can visit this page by tapping on "Sign In" button at top right corner of the top page (/).

ID/password sign-in endpoint: /auth/password

By filling the form and pressing the "Sign In" button at the sign-in page (/signin), a POST request is sent to this endpoint, then redirected to /main if successful or back to /signin if failure.

Google Sign-In endpoint: /auth/google

By tapping on "Sign In with Google" button at either the top page or the sign-in page, a window pops up and lets the user sign in using a Google account. Once succeeded, a POST request is sent to this endpoint, then redirected to /main if successful or back to / or /signin if failure. The POST request contains an id_token to verify if the user is actually signed in to Google.

Main page: /main

You can visit this page if you are signed in.

Sign-out endpoint: /signout

By tapping on the "Sign Out" button at the main page, a GET request is sent to this endpoint, the user is signed out then redirected to /.

Unregister endpoint: /unregister

By tapping on the "Unregister" button at the main page, a POST request is sent to this endpoint, the unregistered user is then redirected to / if successful or back to /main if failure.

In this step, you will implement credential storing feature on user registration.

Capture registration form submission and store the credential

The original registration code POSTs the form to /register. The form involves a name, an email address and a password.

As we'd like to store those credential information after receiving a successful response, let's switch the form submission to an AJAX call.

Create a file named index.js in static/scripts directory.

Capture the registration form submission event. The form has an ID of regForm. You need to prevent the default behavior and instead POST the form data using fetch(). Note that credentials: 'include' is required so that the browser sends cookies as part of the request.

var regForm = document.querySelector('#regForm');
regForm.addEventListener('submit', function(e) {
  e.preventDefault();

  fetch('/register', {
    method: 'POST',
    credentials: 'include',
    body: new FormData(regForm)
  }).then(function(res) {
    // fetch successful
  }, function() {
    app.fire('show-toast', {
      text: 'Registration failed'
    });
  });
});

The error message can be displayed as a toast using Polymer. It's implemented in the base code. Just invoke app.fire('show-toast') like you can see the example above.

The fetch() resolves when the server responds. Check the HTTP status code and if it's 200, proceed with storing the credential by calling navigator.credentials.store(). The PasswordCredential object can be instantiated using the form element you have used to POST. Then transfer to the main page when credential storing is completed.

    if (res.status === 200) {
      if (navigator.credentials) {
        var cred = new PasswordCredential(regForm);
        navigator.credentials.store(cred)
        .then(function() {
          location.href = '/main?quote=You are registered';
        });
      } else {
        location.href = '/main?quote=You are registered';
      }
    } else {
      app.fire('show-toast', {
        text: 'Registration failed'
      });
    }

Combining above code together will look like this. You may copy this code to the index.js.

var regForm = document.querySelector('#regForm');
regForm.addEventListener('submit', function(e) {
  e.preventDefault();

  fetch('/register', {
    method: 'POST',
    credentials: 'include',
    body: new FormData(regForm)
  }).then(function(res) {
    if (res.status === 200) {
      if (navigator.credentials) {
        var cred = new PasswordCredential(regForm);
        navigator.credentials.store(cred)
        .then(function() {
          location.href = '/main?quote=You are registered';
        });
      } else {
        location.href = '/main?quote=You are registered';
      }
    } else {
      app.fire('show-toast', {
        text: 'Registration failed'
      });
    }
  }, function() {
    app.fire('show-toast', {
      text: 'Registration failed'
    });
  });
});

Add autocomplete attributes

In the previous section, the PasswordCredential object used the form element to instantiate, but it requires mappings to ID, password and name . This can be done with semantics.

Add autocomplete attributes to respective input elements inside the form element in templates/index.html:

<input id="csrf_token" type="hidden" name="csrf_token" value="{{csrf_token}}" />
<paper-input id="name" name="name" label="Whatever name" autocomplete="name"
  pattern=".{1,32}" error-message="4-32 letters please" auto-validate required>
  </paper-input>
<paper-input type="email" id="email" name="email" label="Fake email address"
  autocomplete="username" error-message="at least email format, please" auto-validate
  required></paper-input>
<paper-input id="password" type="password" name="password" label="Bogus password"
  autocomplete="new-password" pattern=".{4,32}" error-message="4-32 letters please"
  auto-validate required></paper-input>

Respond with HTTP status codes

The server should handle AJAX calls by responding with HTTP status code instead of redirections. Open main.py and edit the following lines.

On line 233, respond with 400 Bad Request when email or password is missing:

return make_response('Bad Request', 400)

On line 254, respond with 200 OK when registration succeeded:

return make_response('Registered', 200)

Append index.js to the HTML

Finally, add a script tag to load index.js in templates/layout.html.

Insert following code to the bottom of the HTML, beneath other script tags.

{% if path == '/' %}
<script src="scripts/index.js"></script>
{% endif %}

Try it out

You've implemented everything required to store credentials on user registration. Try to register yourself and see if it pops up a password saving dialog:

If it's not working as expected, please check step01 directory and see what went wrong.

If saving password prompt doesn't show up, check if your preference at chrome://settings is set properly once again.

In this step, you will implement credential storing feature on user sign-in.

Capture sign-in form submission and store the credential

Create signin.js in static/scripts directory and implement the code. The differences from the user registration are:

var form = document.querySelector('#form');
form.addEventListener('submit', function(e) {
  e.preventDefault();

  fetch('/auth/password', {
    method: 'POST',
    credentials: 'include',
    body: new FormData(form)
  }).then(function(res) {
    if (res.status === 200) {
      if (navigator.credentials) {
        var cred = new PasswordCredential(form);
        navigator.credentials.store(cred)
        .then(function() {
          location.href = '/main?quote=You are signed in';
        });
      } else {
        location.href = '/main?quote=You are signed in';
      }
    } else {
      app.fire('show-toast', {
        text: 'Authentication failed'
      });
    }
  }, function() {
    app.fire('show-toast', {
      text: 'Authentication failed'
    });
  });
});

Add autocomplete attributes

Modify templates/signin.html by adding autocomplete attributes. Notice the use of current-password instead of new-password for password mapping because this is signing in.

<input id="csrf_token" type="hidden" name="csrf_token" value="{{csrf_token}}" />
<paper-input type="email" id="lemail" name="email" autocomplete="username"
  label="email" error-message="at least email format, please" auto-validate>
  </paper-input>
<paper-input id="lpassword" type="password" name="password"
  autocomplete="current-password" label="password" pattern=".{4,32}" 
  error-message="4-32 letters please" auto-validate required>
  </paper-input>

Respond with HTTP status codes

Modify main.py to allow the server to handle AJAX calls by responding with HTTP status code.

On line 159, respond with 401 Unauthorized when email or password is missing:

return make_response('Authentication failed', 401)

On line 166, respond with 401 Unauthorized when no registered accounts found:

return make_response('Authentication failed', 401)

On line 172, respond with 401 Unauthorized when the account is empty:

return make_response('Authentication failed', 401)

On line 176, respond with 401 Unauthorized when the password doesn't match:

return make_response('Authentication failed', 401)

On line 181, respond with 200 OK when successfully authenticated:

return make_response('Authenticated', 200)

Append signin.js to the HTML

Now let's append a script tag to load singin.js in templates/layout.html.

Insert the following code to the bottom of the HTML, beneath the other script tags:

{% if path == '/signin' %}
<script src="scripts/signin.js"></script>
{% endif %}

Try it out

You've now implemented a feature to store credentials when a user signs in. If there's already a stored credential, remove it either at the address bar by clicking on a key icon or at chrome://settings/passwords.

Then try sign in at /signin using your registered ID/password combination. Notice that storing a credential only happens when the authentication is successful. This can't be achieved if you rely on the form-based credential storing.

If it's not working as expected, please check step02 directory and see what went wrong.

The exciting part of using the Credential Management API is auto sign-in. You can let users automatically sign in to the website without typing a password. It's especially helpful on mobile devices where typing with touch screen is a cumbersome task.

Define autoSignIn() function

The core of auto sign-in feature is the navigator.credentials.get() API. Let's define a function that retrieves a credential and POST it to the server.

Create auto.js in static/scripts directory and define the autoSignIn() function that returns a Promise.

var autoSignIn = function() {
  if (navigator.credentials) {
    // auto sign in logic comes here
  } else {
    return Promise.reject();
  }
};

In order to retrieve a password credential, call navigator.credentials.get() with an option password: true. This prompts the user to select an account by showing an account chooser. Once the user selects an account, resolving function receives a PasswordCredential instance. If the user selects to skip this step by tapping on "Cancel", undefined is passed.

    return navigator.credentials.get({
      password: true
    }).then(function(cred) {
      if (cred) {
        // a PasswordCredential is passed
      } else {
        return Promise.reject();
      }
    });

You can POST the password credential object to the server by passing it as the credentials value in options for fetch().

fetch('/auth/password', {
  method: 'POST',
  credentials: cred
});

Given those caveats, the fetching looks something like this:

        var form = new FormData();
        var csrf_token = document.querySelector('#csrf_token').value;
        form.append('csrf_token', csrf_token);

        switch (cred.type) {
          case 'password':
            cred.additionalData = form;
            cred.idName = 'email';
            return fetch('/auth/password', {
              method: 'POST',
              credentials: cred
            });
        }
        return Promise.reject();

Check the status code from fetch(), only resolve if the request was successful.

    }).then(function(res) {
      if (res.status === 200) {
        return Promise.resolve();
      } else {
        return Promise.reject();
      }
    });

Finally, combine all above code together:

var autoSignIn = function() {
  if (navigator.credentials) {
    return navigator.credentials.get({
      password: true
    }).then(function(cred) {
      if (cred) {
        var form = new FormData();
        var csrf_token = document.querySelector('#csrf_token').value;
        form.append('csrf_token', csrf_token);

        switch (cred.type) {
          case 'password':
            cred.additionalData = form;
            cred.idName = 'email';
            return fetch('/auth/password', {
              method: 'POST',
              credentials: cred
            });
        }
        return Promise.reject();
      } else {
        return Promise.reject();
      }
    }).then(function(res) {
      if (res.status === 200) {
        return Promise.resolve();
      } else {
        return Promise.reject();
      }
    });
  } else {
    return Promise.reject();
  }
};

We now have autoSignIn() available. This can be used in 2 occasions.

First is when a user taps on "Sign-In". Show an account chooser and let the user select one to sign in with.

Second is when a user lands on the website. Let the user automatically sign in without asking any explicit actions if possible. Otherwise, exit silently.

Invoke autoSignIn() when pressing Sign-In button

Open templates/layout.html and remove a tag from line 124 so that you can inject a JavaScript code before moving on.

<paper-button id="signin" raised>Sign In</paper-button>

In static/scripts/index.js, create an event listener to click of #signin and call autoSignIn(). If resolved, it means a user successfully signed in via an account chooser. Let the user move on to the main page (/main), otherwise to the sign-in page (/signin).

var signin = document.querySelector('#signin');
signin.addEventListener('click', function() {
  autoSignIn()
  .then(function() {
    location.href = '/main?quote=You are signed in';
  }, function() {
    location.href = '/signin';
  });
});

Invoke autoSignIn() upon landing the page

Open static/scripts/auto.js again and append a code that calls autoSignIn(). If resolved, move on to the main page, otherwise to the sign-in page.

autoSignIn().then(function() {
  location.href = '/main?quote=You are automatically signed in';
}, function() {
  console.log('auto sign-in skipped');
});

Append auto.js to the HTML

Now let's append the auto.js in templates/layout.html. This time you don't need conditionals.

<script src="scripts/auto.js"></script>

Try it out

You've implemented the auto sign-in feature. Try sign out and see how it works.

You should notice that an account chooser shows up at first attempt to sign in. Yay! Click on the account to sign in.

But wait, try signing out. Do you see "Signing in as ..." pop up?

This forces you to never sign out. This is annoying, but this is not a bug. How do we address this odd state?

Check step03 directory to see if there's anything odd other than the one described above.

Use "mediation mode" to prevent the auto-signed-back-in-unexpectedly behavior. Once you turn on the mediation mode, auto sign-in is prevented. Sign-in only occurs with explicit user action.

Enable mediation mode when a user signs out

Open templates/layout.html and remove a tag from line 126 so that you will be able to inject a JavaScript code before moving on.

<paper-button id="signout" raised>Sign Out</paper-button>

Create main.js in static/scripts directory, define an event listener to click of #signout and call the navigator.credentials.requireUserMediation(). This is enables mediation mode. Once it resolves, you can forward the user to /signout.

var signout = document.querySelector('#signout');
signout.addEventListener('click', function() {
  if (navigator.credentials) {
    navigator.credentials.requireUserMediation()
    .then(function() {
      location.href = '/signout';
    });
  } else {
    location.href = '/signout';
  }
});

Enable mediation mode when a user unregisters

In static/scripts/main.js, detect the form submission upon user unregistration. Upon form submission, you need to prevent default behavior and instead POST the form data using fetch() to /unregister. Note that credentials: 'include' is required so that the browser sends cookies as part of the request.

var unregForm = document.querySelector('#unregForm');
unregForm.addEventListener('submit', function(e) {
  e.preventDefault();

  fetch('/unregister', {
    method: 'POST',
    credentials: 'include',
    body: new FormData(unregForm)
  }).then(function(res) {
    if (res.status === 200) {
      // successful unregistration
    } else {
      app.fire('show-toast', {
        text: 'Unregister failed'
      });
    }
  }, function() {
    app.fire('show-toast', {
      text: 'Unregister failed'
    });
  });
});

Upon successful unregistering, call navigator.credentials.requireUserMediation().

      if (navigator.credentials) {
        navigator.credentials.requireUserMediation()
        .then(function() {
          location.href = '/?quote=You are unregistered';
        });
      } else {
        location.href = '/?quote=You are unregistered';
      }

Combining above code looks like this (append this to static/scripts/main.js).

var unregForm = document.querySelector('#unregForm');
unregForm.addEventListener('submit', function(e) {
  e.preventDefault();

  fetch('/unregister', {
    method: 'POST',
    credentials: 'include',
    body: new FormData(unregForm)
  }).then(function(res) {
    if (res.status === 200) {
      if (navigator.credentials) {
        navigator.credentials.requireUserMediation()
        .then(function() {
          location.href = '/?quote=You are unregistered';
        });
      } else {
        location.href = '/?quote=You are unregistered';
      }
    } else {
      app.fire('show-toast', {
        text: 'Unregister failed'
      });
    }
  }, function() {
    app.fire('show-toast', {
      text: 'Unregister failed'
    });
  });
});

Respond with HTTP status codes for unregistration

The server is ready to accept the unregistered AJAX call by responding with HTTP status code instead of redirections. Open main.py and edit following parts.

On line 263, respond with 401 Unauthorized when the ID is missing:

return make_response('Authentication failed', 401)

On line 266, respond with 401 Unauthorized when no registered accounts found:

return make_response('Authentication failed', 401)

On line 271, respond with 401 Unauthorized when the detected account is empty:

return make_response('Authentication failed', 401)

On line 277, respond with 200 OK when unregistration succeeded:

return make_response('Unregistered', 200)

Reflect the mediation status on auto sign-in

There's a flag to recognize the mediation mode to auto sign-in navigator.credentials.get() . By adding an option unmediated: true, it respects the mediation mode and resolves gracefully with undefined without asking the user to choose an account if the user is in mediation mode and following conditions are not met:

Open static/scripts/auto.js and add unmediated as an argument to autoSignIn() and add it as an option of navigator.credentials.get().

var autoSignIn = function(unmediated) {
  if (navigator.credentials) {
    return navigator.credentials.get({
      password: true,
      unmediated: unmediated
    })
    .then(function(cred) {
      if (cred) {

Use true for autoSignIn() on landing page.

autoSignIn(true).then(function() {
  location.href = '/main?quote=You are automatically signed in';
}, function() {
  console.log('auto sign-in skipped');
});

Open static/scripts/index.js and use false as an argument for autoSignIn().

var signin = document.querySelector('#signin');
signin.addEventListener('click', function() {
  autoSignIn(false)
  .then(function() {
    location.href = '/main?quote=You are signed in';
  }, function() {
    location.href = '/signin';
  });
});

Append main.js to the HTML

Now let's append the main.js in templates/layout.html.

{% if path == '/main' %}
<script src="scripts/main.js"></script>
{% endif %}

Try it out

You've implemented a feature to enable the mediation mode. You should now be able to sign out without auto-sign-back-in-unexpectedly.

If it's not working as expected, compare with step04 directory and see what went wrong.

At the final step, we will add federation support using Google Sign-In.

You can now sign in and out without any problems as long as you are using ID/password. What about federation? Let's finally make Google Sign-In work with the Credential Management API and enable auto sign-in using federated accounts.

Store credentials on signing in using Google Sign-In

Using Google's federation feature is out of scope for this codelab, but we will use the Google Sign-In JavaScript library for convenience. Once a user tries to sign in with Google, this library pops up a window and lets the user choose an account, authenticate/authorize, then close the window with the account information available via JavaScript.

Don't worry, most of the code required for those steps are defined in static/scripts/federation.js. You can just call gSignIn() to receive a promise that resolves with a GoogleUser object.

Open static/scripts/app.js. In order to verify the authenticated Google account, the existing code constructs a form element and submits it to the server. The request contains an id_token (along with a csrf_token as discussed earlier):

We'll utilize an AJAX call to submit the id_token.

Upon successful authentication with Google, a promise resolves with a GoogleUser object. You can send the id_token contained in the object to the server (along with the csrf_token) and authenticate with our end.

  gSignIn()
  .then(function(googleUser) {
    // Successful Google Sign-In authentication
  }).then(function() {
    location.href = '/main?quote=You are signed in with Google SignIn';
  }, function() {
    app.fire('show-toast', {
      text: 'Google Sign-In failed'
    });
  });

Use FormData to construct the data to POST. Append id_token and csrf_token.

    var form = new FormData();
    form.append('id_token', googleUser.getAuthResponse().id_token);
    form.append('csrf_token', document.querySelector('#csrf_token').value);

Use fetch() to POST the FormData to /auth/google. Note that credentials: 'include' is required so that the browser will send cookies as part of the request.

    return fetch('/auth/google', {
      method: 'POST',
      credentials: 'include',
      body: form
    }).then(function(res) {
      // fetch successful
    });

The fetch() resolves when the server responds. Check the HTTP status code and if it's 200, proceed with storing the credential by calling navigator.credentials.store(). The FederatedCredential object can be instantiated by setting individual params. Use GoogleUser object to obtain those params. By returning a promise, you can forward the user to the main page (/main) if resolved, otherwise show an error.

      if (res.status === 200) {
        if (navigator.credentials) {
          var profile = googleUser.getBasicProfile();
          var cred = new FederatedCredential({
            id: profile.getEmail(),
            name: profile.getName(),
            iconURL: profile.getImageUrl(),
            provider: GOOGLE_SIGNIN
          });
          return navigator.credentials.store(cred);
        } else {
          return Promise.resolve();
        }
      } else {
        return Promise.reject();
      }

Combining above code together looks like this:

var gsignin = document.querySelector('#gsignin');
gsignin.addEventListener('click', function() {
  gSignIn()
  .then(function(googleUser) {
    // Now user is successfully authenticated with Google.
    // Send ID Token to the server to authenticate with our server.
    var form = new FormData();
    form.append('id_token', googleUser.getAuthResponse().id_token);
    form.append('csrf_token', document.querySelector('#csrf_token').value);

    return fetch('/auth/google', {
      method: 'POST',
      credentials: 'include',
      body: form
    }).then(function(res) {
      if (res.status === 200) {
        if (navigator.credentials) {
          var profile = googleUser.getBasicProfile();
          var cred = new FederatedCredential({
            id: profile.getEmail(),
            name: profile.getName(),
            iconURL: profile.getImageUrl(),
            provider: GOOGLE_SIGNIN
          });
          return navigator.credentials.store(cred);
        } else {
          return Promise.resolve();
        }
      } else {
        return Promise.reject();
      }
    });
  }).then(function() {
    location.href = '/main?quote=You are signed in with Google SignIn';
  }, function() {
    app.fire('show-toast', {
      text: 'Google Sign-In failed'
    });
  });
});

And again, modify main.py and allow the server to handle AJAX calls by responding with HTTP status code. Edit following parts.

On line 195, respond with 401 Unauthorized when the id_token could not be verified:

return make_response('Authentication failed', 401)

On line 218, respond with 200 OK when signing in with Google account succeeded:

return make_response('Authenticated', 200)

Defer autoSignIn() until Google Sign-In is initialized

You have implemented most of the code required to enable auto sign-in using Google Sign-In. However, when landing on the website, it's highly possible that autoSignIn() fails because Google Sign-In isn't initialized yet. The initialization happens async and autoSignIn() needs to wait for that to finish.

To solve this, open static/scripts/federation.js and let Google Sign-In initialization return a promise.

// Initialize Google Sign-In
var googleAuthReady = (function() {
  return new Promise(function(resolve) {
    gapi.load('auth2', function() {
      gapi.auth2.init().then(function() {
        return resolve();
      });
    });
  });
})();

Using the googleAuthReady variable, you can defer calling autoSignIn() until the initialization finishes. Open static/scripts/auto.js and replace the call to autoSignIn() with following code:

googleAuthReady.then(function() {
  return autoSignIn(true);
}).then(function() {
  location.href = '/main?quote=You are automatically signed in';
}, function() {
  console.log('auto sign-in skipped');
});

Enable the federated account as an option for auto sign-in

Finally, enable the federated account as an option to sign in both when the user is landing the website and tapping on "Sign-In".

Open static/scripts/auto.js and add federated as an option to navigator.credentials.get() and pass an array to it that contains GOOGLE_SIGNIN. GOOGLE_SIGNIN is defined in static/scripts/federation.js.

  if (navigator.credentials) {
    return navigator.credentials.get({
      password: true,
      federated: {
        providers: [ GOOGLE_SIGNIN ]
      },
      unmediated: unmediated
    }).then(function(cred) {
      if (cred) {

This allows the browser to show federated accounts as options when a user gets prompted with the account chooser. After user selects a federated account, the resolving credential is a type of federated. Also examine the .provider of the credential object and switch depending on the provider as well.

Initiate the federation steps by kicking relevant libraries. For example, if the provider is Google, use the Google Sign-In library.

Luckily, we already have gSignIn(), you can simply call it then POST the resulting id_token to the server as you've done earlier.

You can also reuse the FormData you've constructed and is already filled with the CSRF token in the earlier step.

        switch (cred.type) {
          case 'password':
            cred.additionalData = form;
            cred.idName = 'email';
            return fetch('/auth/password', {
              method: 'POST',
              credentials: cred
            });
          case 'federated':
            switch (cred.provider) {
              case GOOGLE_SIGNIN:
                return gSignIn(cred.id)
                .then(function(googleUser) {
                  var id_token = googleUser.getAuthResponse().id_token;
                  form.append('id_token', id_token);
                  return fetch('/auth/google', {
                    method: 'POST',
                    credentials: 'include',
                    body: form
                  });
                });
            }
        }

Try it out

You should now have a fully functional website with auto sign-in using the Credential Management API.

If it's not working as expected, check step05 directory and see what went wrong.

Play around and enjoy!

Your website is now ready to auto sign-in users!

What we've covered

Next Steps

Learn More