WebAuthn quick start: Web SDK (Older SDK)

Get started with WebAuthn APIs using our WebAuthn SDK. This describes how to quickly integrate WebAuthn registration and authentication into your application.

Note

This guide describes integrating using the older WebAuthn SDK. The new Platform SDK offers all the same functionality and more. While the older SDK is still supported for existing integrations, new features will only be supported by the Platform SDK.

Return to the Platform SDK guide

Sample flows

Here are samples of some flows that implement WebAuthn biometric login using our WebAuthn Web SDK. These are simplified representations to help you get to know Mosaic APIs in context. There are many different ways to implement this and this is just an example.

New credential registration

This flow represents a user registering new WebAuthn credentials. Mosaic APIs are shown in pink along with the relevant integration steps.

After initializing the SDK, the client validates that the device supports WebAuthn. An authorized session is then created to establish a secure context for registration. For a better UX, the SDK prepares for registration by fetching the challenge from the Mosaic Server and storing it locally. Once the user is ready to register their credential, the SDK tells the browser to create credentials, which may require the user to verify (e.g., via TouchID). Once completed, an authorization code is returned to the client to exchange for user tokens via their backend. Once tokens are validated, the user's credential is registered and they're logged in.

Single device authentication

This flow represents an existing user authenticating using registered credentials which exist on the device, and assumes that you've collected the username before initiating authentication. Mosaic APIs are shown in pink along with the relevant integration steps.

The SDK is initialized. For a better UX, the SDK prepares for authentication by fetching the challenge from the Mosaic backend and storing it locally. Once the user is ready to authenticate, the SDK tells the browser to get credentials, which may require the user to verify (e.g., via TouchID). Once completed, an authorization code is returned to the client to exchange for user tokens. Your client backend exchanges the auth code for ID and access tokens. Once tokens are validated, the user is logged in.

Step 1: Configure your app

To integrate with Mosaic, you'll need an application. From the Applications page, create a new application or use an existing one. The application settings provide client credentials that you'll need for API calls. These credentials are automatically generated when your application is created.

Note
  • Redirect URI is required, although it's not used in the WebAuthn flow. If you're not using any other login method (which do require redirection), enter your website URL here instead. Use HTTPS (e.g., https://login.example.com ), unless using a local environment (e.g., http://localhost ).
  • Enable public sign-up if you manage users using an external system (e.g., external identity provider) or if you want to quickly test WebAuthn registration and authentication without first logging in using a different authentication method.

Step 2: Configure auth method

From the Authentication methods page, configure the WebAuthn login method for your application:

  • For WebAuthn RP ID , add your application's domain (e.g., example.com ). This is the domain to which WebAuthn credentials are registered and used to authenticate.
  • For WebAuthn RP Origin , add the web origin that will be used to request registration and authentication. The origin must match the domain of the RP ID, but may be a subdomain of the RP ID (e.g., https://login.example.com ). The origin must also include the HTTPS scheme and port (if relevant).
TIP

For testing and development, configure the login method for your local environment by setting the RP ID to localhost and the RP origin to http://localhost:(PORT) (e.g., http://localhost:1234).

Step 3: Initialize the SDK

You can install the WebAuthn SDK by adding a script tag with the latest SDK to the relevant pages of your application:

Copy
Copied
<script type="text/javascript"  src="https://cdn.identity.security/authentication-sdk/2.9.0/TsAuthSdk.min.js"></script>

Configure the SDK by calling the init() SDK method, passing the client ID obtained in Step 1. For example:

Copy
Copied
await window.WebAuthnSdk.init('CLIENT_ID', {serverPath: "https://api.transmitsecurity.io/cis"});

Step 4: Register credentials

To implement a WebAuthn registration flow, you'll need to:

  1. Check that the device supports WebAuthn
  2. Create a secure context for registration
  3. Prepare registration
  4. Perform the credential registration

1. Check for WebAuthn support

Before initiating WebAuthn registration, use the isPlatformAuthenticatorSupported() SDK call to check if the device supports WebAuthn.

Copy
Copied
const isBiometricsSupported = await window.WebAuthnSdk.isPlatformAuthenticatorSupported();

2. Start an authorized session

From your backend, create an authorized authentication session for the user in order to provide the secure context required for WebAuthn registration. To do this, send the /auth-session/start-with-authorization request below from your client backend. The API returns the session ID of the created session, which you'll need for subsequent API calls.

In the request below, you should replace the following:

  • USERNAME is a verified username, which should be a representation of the user in your system (such as their email, phone number, or another verifiable username known to the user like account ID).
  • TOKEN is either a client access token or a user access token depending on your login scenario . To quickly test a basic WebAuthn integration (without implementing any additional login methods or the full logic required for your use case), make sure public sign-up is enabled for your application and use a client access token .
Copy
Copied
const basePath = 'v1';
const resp = await fetch(
  `https://api.transmitsecurity.io/cis/v1/auth-session/start-with-authorization`,
  {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      Authorization: 'Bearer TOKEN' // Type of token depends on the use case, as explained above
    },
    body: JSON.stringify({
      username: 'USERNAME'
    })
  }
);

const data = await resp.json();
console.log(data);

3. Prepare registration

Optional

Check if there are users who have already registered biometrics or authenticated with this device. Call the getDeviceUsers() SDK method. It returns a promise that resolves to an array containing usernames or an empty array in case there are no device users or the browser local storage was cleared (e.g., the incognito mode is on).

As soon as the username is known, call the prepareWebauthnRegistration() SDK call as shown below. Pass the username, an optional display name for the user account, as well as the session ID returned upon session creation.

Copy
Copied
await window.WebAuthnSdk.prepareWebauthnRegistration('USERNAME', 'DISPLAY_NAME', 'SESSION_ID');

4. Complete registration

When the user is ready to proceed to device registration (and only after calling prepareWebauthnRegistration()), call the executeWebAuthnRegistration() SDK method. This will prompt the user for biometrics. If successful, it returns a promise that resolves to the authorization code, which you'll exchange for a token via your backend in step 6.

Copy
Copied
const authCode = await window.WebAuthnSdk.executeWebauthnRegistration();

Step 5: Authenticate user

To implement a WebAuthn authentication flow, you'll need to:

  1. Prepare authentication
  2. Complete authentication

1. Prepare authentication

When logging in users with registered devices, call the prepareWebauthnAuthentication() SDK call as soon as the username is known. For example:

Copy
Copied
await window.WebAuthnSdk.prepareWebauthnAuthentication('USERNAME');

2. Complete authentication

When the user is ready to proceed to authentication (and only after calling prepareWebauthnAuthentication()), call the executeWebAuthnAuthentication() SDK method. This will prompt the user for biometrics. If successful, this call returns a promise that resolves to the authorization code, which you'll exchange for a token via your backend in step 6.

Copy
Copied
const authCode = await window.WebAuthnSdk.executeWebauthnAuthentication();

Step 6: Get user tokens

In response to each successful authentication or registration, an authorization code is returned to your client application (frontend). After sending this code to your backend, exchange it for an ID and access token by sending a /oidc/token request like the one below from your backend . Pass your client credentials, along with the authorization code returned by the SDK upon successfully completing authentication or registration.

The user tokens will identify the user via user_id, and include any other alias you've verified and set for the user (such as email or phone number). These tokens should be validated as described here. For more, see the Token Reference.

Copy
Copied
var axios = require('axios');
var qs = require('qs');
var data = qs.stringify({
  'grant_type': 'authorization_code',
  'code': 'CODE',
  'client_id': 'CLIENT_ID',
  'client_secret': 'CLIENT_SECRET',
  'redirect_uri': 'REDIRECT_URI'
});
var config = {
  method: 'post',
  url: 'https://api.transmitsecurity.io/oidc/token',
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded'
  },
  data : data
};

axios(config)
.then(function (response) {
  console.log(JSON.stringify(response.data));
})
.catch(function (error) {
  console.log(error);
});

Full code examples

Here's an example of a registration flow:

Copy
Copied
<html>
  <head>
    <script type="text/javascript" src="https://cdn.identity.security/authentication-sdk/2.9.0/TsAuthSdk.min.js"></script>
    <script>
      const config = {
        clientId: "CLIENT_ID",
        serverPath: "https://api.transmitsecurity.io/cis",
      }

      async function init() {
        // Check if WebAuthn is supported on the current device
        if (!window.WebAuthnSdk.isPlatformAuthenticatorSupported()) {
          alert("WebAuthn is not supported on the current device");
        }
      }

      async function onRegister() {
        // Collect user input
        const username = document.getElementById("username").value;
        const userDisplayName = document.getElementById("userDisplayName").value;

        // Call your backend and start an authorized session
        // You should pass back the 'auth_session_id' you received from the API
        console.log("Starting an authorized session");
        const response = await fetch("https://YOUR_BACKEND/start-auth-session");
        const {authSessionId} = await response.json();

        console.log("Initializing WebAuthn SDK");
        window.WebAuthnSdk.init(config.clientId, {serverPath: config.serverPath});

        // Prepare WebAuthn registration using the data obtained from the user and startAuthSession call
        console.log("Preparing WebAuthn registration");
        await window.WebAuthnSdk.prepareWebauthnRegistration(
          username,
          userDisplayName,
          authSessionId
        );

        // Execute the registration process
        // You should get the code back from this call
        console.log("Executing WebAuthn Registration");
        const code = await window.WebAuthnSdk.executeWebauthnRegistration();

        // Exchange the code for an access token in your backend
        console.log("Exchanging code for access token");
        await fetch("https://YOUR_BACKEND/code-exchange", {
          method: 'POST',
          headers: {
            'Accept': 'application/json',
            'Content-Type': 'application/json'
          },
          body: JSON.stringify({code})
        });

        alert(`User ${username} registered successfully!`);
      }
    </script>
  </head>
  <body onload="init()">
    <div>
      Username<br/>
      <input id="username"/>
    </div>
    <div>
      User display name<br/>
      <input id="userDisplayName"/>
    </div>
    <button id="register" onclick="onRegister()">Register WebAuthn</button>
  </body>
</html>

Here's an example of an authentication flow:

Copy
Copied
<html>
  <head>
    <script type="text/javascript" src="https://cdn.identity.security/authentication-sdk/2.9.0/TsAuthSdk.min.js"></script>
    <script>
      const config = {
        clientId: "CLIENT_ID",
        serverPath: "https://api.transmitsecurity.io/cis",
      }

      /**
       * We assume the user was already registered in the past on this device.
       * Therefore we can direct him to an authentication flow and there's no need to
       * check if biometrics is supported.
       */
      async function onAuthenticate() {
        // Collect user input
        const username = document.getElementById("username").value;

        console.log("Initializing WebAuthn SDK");
        window.WebAuthnSdk.init(config.clientId, {serverPath: config.serverPath});

        // Prepare WebAuthn authentication
        console.log("Preparing WebAuthn authentication");
        await window.WebAuthnSdk.prepareWebauthnAuthentication(username);

        // Execute the authentication process
        // You should get the code back from this call
        console.log("Executing WebAuthn authentication");
        const code = await window.WebAuthnSdk.executeWebauthnAuthentication();

        // Exchange the code for an access token in your backend
        console.log("Exchanging code for access token");
        await fetch("https://YOUR_BACKEND/code-exchange", {
          method: 'POST',
          headers: {
            'Accept': 'application/json',
            'Content-Type': 'application/json'
          },
          body: JSON.stringify({code})
        });

        alert(`User ${username} logged in successfully!`);
      }
    </script>
  </head>
  <body>
    <div>
      Username<br/>
      <input id="username"/>
    </div>
    <button id="authenticate" onclick="onAuthenticate()">Login</button>
  </body>
</html>

Next steps

Once you've tested your basic WebAuthn integration, you can complete your implementation: