Ideem FIDO2 Authenticator

Confidential - All materials are intended to be used for informational purposes only and are the sole intellectual property of Ideem, Inc.

For questions and feedback, contact support@useideem.com.

Introduction

Ideem provides this client software development kit (ZSM Client SDK) for your use in integrating FIDO2 Authenticator into your application.

Here is a high level view of the interfaces exposed by the ZSM Client SDK:

Ideem Client SDK

The Ideem System

The ZSM Client SDK works along with other Ideem system components to perform the available operations. Those components are:

  • ZSM Crypto Module: The ZSM Crypto Module provides the underlying MPC-based cryptography at the core of Ideem’s ZSM and is FIPS 140-3 validated.
  • ZSM Client SDK: The Client SDK contains the ZSM Crypto Module and provides programmatic access to Ideem’s interfaces for FIDO2 Authentication.
  • ZSM Server: The Cryptographic Server contains the ZSM Crypto Module and participates with the Client SDK in all MPC-based operations.
  • Authentication Server: The Authentication Server is responsible for managing consumer profiles, integrating with authentication services, and providing WebAuthn relying party capabilities.
  • Admin Console: The Admin Console provides our customers application management, consumer management, usage monitoring, and troubleshooting capabilities.

Here is a high level view of how these system components work together:

Ideem System Overview

ZSM Client SDK Overview

This document covers the installation and use of the ZSM Client SDK. The ZSM Client SDK offers interfaces into Ideem's cryptographic authentication services for implementing FIDO2 Authenticator into your appliction.

FIDO2 Authentication

If you have an existing relying party infrastructure in place, you can use Ideem's FIDO Authenticator interfaces to perform Attestation (WebAuthn Create) and Assertion (WebAuthn Get) operations.

The FIDO2Client class exposes these interfaces:

webauthnRetrieve()

webauthnRetrieve() is used to determine if an end user is already enrolled. If they are enrolled, their ZSM credentials are returned.


webauthnCreate()

webauthnCreate() is used to enroll the consumer, which generates their ZSM credentials. After successful enrollment, the credential ID and Public Key associated with it are returned. This data can then be stored in association with the consumer ID, and used for future webauthnGet() verification operations.


webauthnGet()

webauthnGet() is used to verify the consumer against their existing ZSM credential set. During webauthnGet() processing, a challenge from a relying party server is signed using ZSM MPC. The signed challenge can then be verified using the Public Key stored following the webauthnCreate() operation.


FIDO2 Authentication Sequence Diagrams

Example Enrollment Flow After performing strong authentication for a consumer, you cryptographically bind them to their device using webauthnCreate().

Enrollment

Example Verification Flow On subsequent logins, you perform a silent 2FA for the consumer, using the webauthnGet().

Verification

Example Step Up Verification Flow When the consumer initiates a transaction requiring re-verification, e.g., a large money transfer, you can perform a silent verification using webauthnGet() before allowing the transaction.

Re-Verification

API Versioning and Backward Compatibility

Ideem uses semantic versioning of its APIs. Semantic versioning is an industry standard approach around how API versions are named. It defines a version number in the format of X.Y.Z where X, Y, and Z are the major, minor, and patch versions.

In practicality, Semantic Versioning is implemented on a spectrum of strictness. We take a flexible approach in the following way:

  • We only increase the major version for changes of a significant breaking nature. If this version number changes, significant changes must be made by all users of our API.
  • We may increase the minor version for minor breaking changes instead of increasing the major version. We would only take such action when that change has a very limited scope and the impact has been discussed and agreed upon by the impacted parties. A concrete example of this is if we change a special feature used by one or two of our customers in a breaking way in conjunction with agreement from these impacted customers. But the change otherwise does not impact our overall customer base.
  • In a strict interpretation, the patch version would only be increased for bug fixes. We may increase our patch version for minor new features or enhancements to existing features so long as these changes do not represent a breaking change.

Ideem will support the current and one prior major version of each API for a 24-month period, including all minor, and patch updates to those major versions.


Let's Get Started

In the following pages, you will learn how to:

  1. Add the ZSM Client SDK to your application project
  2. Use the interfaces for FIDO2 Authentication and Universal Multi-Factor Authentication (UMFA).

Working with Browser Applications

This section will focus on integration of the ZSM Client SDK into browser-based applications.

Languages Supported

  • JavaScript
  • TypeScript

Supported Web Frameworks

  • React: 16.8 and later
  • VueJS: 2.5.4 and later
  • Angular: 6 and later
  • Svelte: 3 and later

Supported Browsers

  • Google Chrome: 57 and later
  • Mozilla Firefox: 52 and later
  • Safari: 11 and later
  • Microsoft Edge: 16 and later
  • Opera: 44 and later

Example Browser Project Files

Example implementations are included in the ZSM Client SDK in the folder examples.

Installation & Setup for Browser Applications

Adding the ZSM Client SDK into your Browser project

The ZSM Client SDK is a package that provides programmatic access to Ideem’s interfaces used to integrate FIDO2 Authentication into your application. This document will guide you through the process of adding the ZSM Client SDK to your Browser app project.


Step #1: Install the NPM Package

From within your project directory, run the following command to install the ZSM Client SDK:

npm install @ideem/zsm-client-sdk --save

After installation, you should see the following in your package.json file (#.#.## will depend on the version installed):

"dependencies": {
    "@ideem/zsm-client-sdk": "^#.#.##"
}

IMPORTANT: You can ensure that, during the development process, the ZSM Client SDK is always up to date by using the npm update command.

OPTIONAL: You can also change the "^#.#.##" in your package.json to "latest" to always get the latest version (although it is recommended that you specify a specific version, or version range when rolling to production to avoid breaking changes as future releases are published):

"dependencies": {
    "@ideem/zsm-client-sdk": "latest"
}

Step #2: Import the ZSM Client SDK

The ZSM Client SDK can be imported into your application in one of three ways:

1. ES Modules/Frameworks/Modern Universal ("import" syntax)

The SDK can be included in ES module applications using the import statement. (This includes virtually all modern browsers and Node.js versions that support ES modules; which includes almost every JS framework).

(This also includes the use of the type="module" attribute in the <script> tag, as well as the use of the --experimental-modules flag in Node.js.)

Frameworks (and Node.js with ES modules/--experimental-modules flag)

import { FIDO2Client } from './zsm-client-sdk.js';

(or, using the type="module" attribute in the <script> tag of vanilla HTML)

<script type="module">
    import { FIDO2Client } from "./node_modules/@ideem/zsm-client-sdk/zsm-client-sdk.js";
</script>

2. Node.js/CommonJS ("require" syntax):

The SDK can be included in Node.js and CommonJS applications using the require function.

const { FIDO2Client } = require('./zsm-client-sdk.js');

3. Browser/HTML:

The SDK can be included in HTML files using a <script> tag. The SDK will be available as a global object named ZSMClientSDK.

<script src="./node_modules/@ideem/zsm-client-sdk/zsm-client-sdk.js">
    const {FIDO2Client} = ZSMClientSDK;
</script>

Step #3: Set up the ZSM Configuration File

Within your application, create a .json file or JSON object to store the ZSM application configuration. It should contain the following properties:

{ 
    "application_id"           : "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
    "host_url"                 : "https://zsm-authenticator-demo.useideem.com/",
    "application_environment"  : "TEST",
    "api_key"                  : "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
}

These values are provided by Ideem and are unique to your application, although testing versions are pre-populated in the Sample Apps specific to the language you are using.

Configuration Properties

Property NameData TypDescriptionDefault Value
application_idstringThe application ID to be used during the U2FA processprovided by Ideem; test value available in sample config
host_urlBooleanThe URL to your region-specific ZSM serverprovided by Ideem; demo server specified in sample config
api_keystringThe API key to be used during the U2FA processprovided by Ideem; test value available in sample config
application_environmentstringThe application environment to be used during the U2FA processTEST

Step #4: Initialize the ZSM Client SDK

After importing the ZSM Client SDK and setting up the configuration file, you can initialize the client SDK - being sure to pass it the configuration object you created in the previous step - as follows:

FIDO2 Client:

    const fido2Client = new FIDO2Client(config);

FIDO2 APIs for Browser Applications

Ideem's FIDO2 Authenticator interfaces enable seamless integration with an existing Relying Party (RP) infrastructure. The Relying Party is a critical component in the WebAuthn framework, typically representing the server that interacts with users’ authenticators to handle the registration and authentication processes. The Relying Party is responsible for securely storing users' credential IDs, public keys, and managing authentication challenges.

Through these interfaces, you can determine whether a user has already been enrolled (i.e., their device has been cryptographically bound to an account). The interfaces provide the ability to either create an enrollment if none exists or verify an existing enrollment. FIDO2 WebAuthn functions also support re-authentication for scenarios that require step-up authentication, such as sensitive transactions or multi-factor authentication.

The following sections describe the core API methods used to interact with WebAuthn, detailing how to retrieve enrollment status, create new credentials, and verify users.


Relying Party Overview

A Relying Party (RP) is a system or service that requests the user's authentication via WebAuthn. In the FIDO2/WebAuthn architecture, the RP plays the crucial role of initiating the registration and authentication process, sending appropriate challenges to the user’s authenticator, and verifying the signed responses.

When a user registers with a Relying Party, the RP generates a challenge and sends it to the authenticator. Upon successful registration, the RP stores the credential ID and the associated public key for future verification of the user's identity. Similarly, during the authentication process, the RP sends another challenge, which the user’s authenticator signs and returns. The RP then verifies the signature using the public key associated with the credential ID.

Ideem's interfaces abstract much of this complexity, allowing developers to focus on integrating FIDO2 authentication into their applications by simply interacting with the webauthnCreate, webauthnRetrieve, and webauthnGet methods.


Interface Definitions

Note that the following interface definitions presuppose that you have already imported the FIDO2Client class from the ZSM Client SDK (@ideem/zsm-client-sdk). If you have not yet done so, please refer to the Web Framework Setup documentation for instructions on how to import the ZSM Client SDK.


Webauthn Retrieve FIDO2Client.webauthnRetrieve() (Check For Existing Credentials)

The webauthnRetrieve method of the FIDO2Client class retrieves the attestation data generated during the WebAuthn creation process. This method allows the Relying Party to check if a user has previously been enrolled, meaning that their device has a stored credential ID linked to their account.

Parameters

Parameter NameData TypeDescription
userIdentifierStringThe unique identifier for the user. This is typically the user's email address or a UUID.

Returns

Parameter NameData TypeDescription
responsePublicKeyCredentialThe retrieved WebAuthn credential containing attestation data*.

The attestation data returned contains cryptographic information needed to verify the user’s identity and ensure that the credential is securely bound to the device.

Usage

JavaScript

FIDO2Client.webauthnRetrieve()
.then(response => {
    console.log("Retrieved attestation data", response);
    // Process attestation data
})
.catch(error => {
    console.error("Error retrieving attestation data:", error);
});

TypeScript

FIDO2Client.webauthnRetrieve()
    .then((response:PublicKeyCredential) => {
        console.log("Retrieved attestation data", response);
        // Process attestation data
    })
    .catch((error: any) => {
        console.error("Error retrieving attestation data:", error);
    });


Webauthn Create FIDO2Client.webauthnCreate() (Create New Credential/Enroll)

The webauthnCreate method initiates the creation of a new WebAuthn credential by leveraging the PublicKeyCredentialCreationOptions. This method is used during user registration to create a public-private key pair, which is cryptographically bound to the user and device.

Once the credential is created, the Relying Party securely stores the credential ID and public key for future authentication. The client-side device will keep the private key securely stored within the authenticator.

The process follows the FIDO2 standard, ensuring that the public-private key pair is securely created and attested.

Parameters

Parameter NameData TypeDescription
create_optionsPublicKeyCredentialCreationOptionsA JSON object representing the creation options for WebAuthn credentials.

Returns

Parameter NameData TypeDescription
credentialPublicKeyCredentialThe created WebAuthn credential object.

Usage

JavaScript

const publicKeyOptions = {
    challenge: new Uint8Array([117, 61, 252, 231, 191, 241, ...]),
    rp: { id: "acme.com", name: "ACME Corporation" },
    user: {
        id: new Uint8Array([79, 252, 83, 72, 214, 7, 89, 26]),
        name: "jamiedoe",
        displayName: "Jamie Doe"
    },
    pubKeyCredParams: [{ type: "public-key", alg: -7 }]
};

FIDO2Client.webauthnCreate(publicKeyOptions)
    .then(credential => {
        console.log("Credential created successfully", credential);
        // Handle successful creation, access credential response
    })
    .catch(error => {
        console.error("Error creating credential:", error);
    });

TypeScript

const publicKeyOptions:PublicKeyCredentialCreationOptions = {
  challenge: new Uint8Array([117, 61, 252, 231, 191, 241, ...]),
  rp: { id: "acme.com", name: "ACME Corporation" },
  user: {
    id: new Uint8Array([79, 252, 83, 72, 214, 7, 89, 26]),
    name: "jamiedoe",
    displayName: "Jamie Doe"
  },
  pubKeyCredParams: [{ type: "public-key", alg: -7 }]
};

FIDO2Client.webauthnCreate(publicKeyOptions)
    .then((credential:PublicKeyCredential) => {
        const response = credential.response as AuthenticatorAttestationResponse;

        // Access attestationObject ArrayBuffer
        const attestationObj:ArrayBuffer = response.attestationObject;

        // Access client JSON
        const clientJSON:PublicKeyCredential = response.clientDataJSON;

        console.log("Credential created successfully", credential);
    })
    .catch((error: any) => {
        console.error("Error creating credential:", error);
    });


Webauthn Get FIDO2Client.webauthnGet() (Authenticate/Verify User)

The webauthnGet method retrieves a credential object based on the PublicKeyCredentialRequestOptions. This method is used to authenticate the user by having their authenticator sign the provided challenge. The signed challenge is then sent back to the Relying Party, which verifies the signature using the previously stored public key.

This method is central to the authentication process, ensuring that only the correct device and user (who possess the private key) can successfully sign the challenge and prove their identity.

Parameters

Parameter NameData TypeDescription
get_optionsPublicKeyCredentialRequestOptionsA JSON object representing the options for retrieving WebAuthn credentials.

Returns

The promise resolves with the following parameters:

Parameter NameData TypeDescription
assertionPublicKeyCredentialThe WebAuthn credential assertion object.

Usage

JavaScript

const requestOptions = {
    challenge: new Uint8Array([117, 61, 252, 231, 191, 241, ...]),
    allowCredentials: [{ type: "public-key", id: new Uint8Array([79, 252, 83, 72, 214, 7, 89, 26]) }],
    userVerification: "preferred"
};

FIDO2Client.webauthnGet(requestOptions)
    .then(assertion => {
        console.log("Assertion obtained successfully", assertion);
        // Handle successful assertion
    })
    .catch(error => {
        console.error("Error obtaining assertion:", error);
    });

TypeScript

const requestOptions: PublicKeyCredentialRequestOptions = {
  challenge: new Uint8Array([117, 61, 252, 231, 191, 241, ...]),
  allowCredentials: [{ type: "public-key", id: new Uint8Array([79, 252, 83, 72, 214, 7, 89, 26]) }],
  userVerification: "preferred"
};

FIDO2Client.webauthnGet(requestOptions)
    .then((assertion: PublicKeyCredential) => {
        console.log("Assertion obtained successfully", assertion);
        // Handle successful assertion
    })
    .catch((error: any) => {
        console.error("Error obtaining assertion:", error);
    });


Unenroll FIDO2Client.webauthnDelete() (Remove user's enrolled credentials from the device)

The webauthnDelete method of the FIDO2Client class removes the specified, enrolled user's credentials from the device the user is actively logged in with. This effectively deletes any credentials associated with the user, preventing future authentication using those credentials, until the user re-enrolls on said device.

Parameters

Parameter NameData TypeDescription
userIdentifierStringThe unique identifier for the user. This is typically the user's email address or a UUID.

Returns

Parameter NameData TypeDescription
responsePromiseReturns a promise containing the results of the unenrollment. This can include any one of the following:
true (boolean) : The user's credentials were successfully removed from the device
false (boolean): The user was not enrolled and/or had no valid local credential set
error ( Error ): Unable to unenroll 's identity from this device.

Usage

JavaScript

const deleteResult = await FIDO2Client.webauthnDelete(userIdentifier);
if (deleteResult instanceof Error) throw(deleteResult);                     // Error Condition
if (!deleteResult)  console.warn("User not enrolled");                      // Unenrollment Failed
if (!!deleteResult) console.log("User successfully unenrolled");            // Successful Unenrollment

TypeScript

const deleteResult:boolean|Error = await FIDO2Client.webauthnDelete(userIdentifier);
if (deleteResult instanceof Error) throw(deleteResult);                     // Error Condition
if (deleteResult === false) console.warn("User not enrolled");              // Unenrollment Failed
if (deleteResult === true)  console.log("User successfully unenrolled");    // Successful Unenrollment


Event: FIDO2ClientReady

The FIDO2ClientReady event is dispatched when the FIDO2Client is ready to be used. This event is emitted from the worker thread to the main thread's window object. This event can be listened for - to ensure that the client is fully initialized before attempting to call methods contained within it - and the listener can, upon its firing, be used to trigger any necessary actions or UI updates in your application.

Details

In some implementations, the FIDO2Client may take a short time (typically measured in tens of milliseconds, depending on client system specifications) to initialize, especially if it is being loaded from a remote source or if it is being loaded JIT (Just-In-Time) immediately preceding its use.

As such, a listener for this event can be added to the window object to ensure that the FIDO2Client is fully initialized before attempting to call methods contained within it.

Payload

ParameterTypeDescription
detailBoolean (true)The detail object inside the event will always contain the value true, indicating that the FIDO2Client is ready to be used, but since the event is only emitted once it's already ready, this is a formality and can be ignored.

Usage

JavaScript

window.addEventListener('FIDO2ClientReady', function (event) {
    console.info("FIDO2ClientReady event received!");

    // Perform any additional actions that involve the FIDO2Client, assured that it is ready to be used
});

TypeScript

window.addEventListener('FIDO2ClientReady', function (event: CustomEvent) {
    console.info("FIDO2ClientReady event received!");

    // Perform any additional actions that involve the FIDO2Client, assured that it is ready to be used
});
Note...

The FIDO2ClientReady event is a custom event and is not part of the standard DOM events. It is specific to the FIDO2Client implementation and should be handled accordingly. In most implementations, this event listener should not be necessary, as the FIDO2Client is typically initialized during the page load and will be long-since ready prior to its use. However, in some specific cases, this event may be useful to ensure that the client is fully initialized before attempting to call methods contained within it.


Example Code

This example demonstrates the full process of using Ideem’s FIDO2 WebAuthn API for registration, authentication, and how to customize the Relying Party. The WebAuthnClient can either use the default Relying Party provided by the API or allow you to pass in a custom Relying Party if you want more control over how credential IDs, tokens, or user data are handled.


Example of Default Flow: Registration and Authentication

In this example, we use the default Relying Party provided by the API:

const client = new WebAuthnClient();

// Sign in with username and password
FIDO2Client.signIn('jamiedoe@example.com', 'password123')
.then(() => {
    console.log("Signed in successfully");

    // Start the WebAuthn registration process
    return FIDO2Client.webauthnCreate('jamiedoe@example.com');
})
.then((response) => {
    console.log("WebAuthn registration complete", response);

    // Now authenticate the user using the WebAuthn credential
    return FIDO2Client.webauthnGet('jamiedoe@example.com');
})
.then((data) => {
    console.log("WebAuthn authentication successful", data);
})
.catch((error) => {
    console.error("Error during registration/authentication", error);
});

In this flow:

  • The user signs in using their email and password.
  • If they don’t have a WebAuthn credential, they go through the webauthnCreate process to register.
  • Once registered, they can authenticate using webauthnGet in future logins.


Custom Relying Party Example

If you need more control over how credentials are stored, retrieved, or verified (for example, if you manage your own storage for credential_id and public keys), you can create a custom Relying Party class and pass it into the WebAuthnClient. This gives you full control over how the server interactions are managed.

Here’s an example of a custom Relying Party:

class CustomRelyingParty {
    constructor(host) {
        this.host = host;
        this.state = new RelyingPartyState();
    }

    login(username, password) {
        const loginPayload = {
            email: username,
            password: password,
        };

        return fetch(`${this.host}/custom-api/auth/login`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(loginPayload),
        })
        .then(response => response.json())
        .then(data => {
            this.state = new RelyingPartyState(data);
            return data;
        });
    }

    startRegistration() {
        const payload = { user_id: this.state.userID };
        return fetch(`${this.host}/custom-api/webauthn/registration/start`, {
            method: 'POST',
            headers: {
                'Authorization': `Bearer ${this.state.token}`,
                'Content-Type': 'application/json',
            },
            body: JSON.stringify(payload),
        })
        .then(response => response.json());
    }

    finishRegistration(credential) {
        const payload = {
            user_id: this.state.userID,
            credential,
        };

        return fetch(`${this.host}/custom-api/webauthn/registration/finish`, {
            method: 'POST',
            headers: {
                'Authorization': `Bearer ${this.state.token}`,
                'Content-Type': 'application/json',
            },
            body: JSON.stringify(payload),
        })
        .then(response => response.json());
    }

    // Implement other methods (startAuthentication, finishAuthentication, etc.) similarly
}

// Use the custom Relying Party in the WebAuthnClient
const customRelyingParty = new CustomRelyingParty("https://your-custom-host.com");
const client = new WebAuthnClient(customRelyingParty);

// Custom sign in flow
FIDO2Client.signIn('janedoe@example.com', 'securePassword!')
    .then(() => {
        console.log("Signed in using custom Relying Party");

        // Start the registration process using the custom Relying Party
        return FIDO2Client.webauthnCreate('janedoe@example.com');
    })
    .then((response) => {
        console.log("Custom WebAuthn registration complete", response);

        // Now authenticate the user using the custom Relying Party
        return FIDO2Client.webauthnGet('janedoe@example.com');
    })
    .then((data) => {
        console.log("Custom WebAuthn authentication successful", data);
    })
    .catch((error) => {
        console.error("Error during registration/authentication", error);
    });


Explanation

  1. CustomRelyingParty Class:

    • This class mimics the behavior of the default RelyingParty class, but it uses a custom API endpoint (/custom-api/...) for managing authentication and WebAuthn interactions.
    • It maintains the same methods as the default Relying Party, such as login, startRegistration, finishRegistration, and more.
  2. Usage:

    • You instantiate your custom Relying Party and pass it into the WebAuthnClient constructor. This allows the WebAuthnClient to interact with your custom API.
    • From here, the WebAuthnClient manages the WebAuthn process, while the custom Relying Party manages the server interactions.
  3. Flexibility:

    • By implementing a custom Relying Party, you can tailor the behavior to match your own backend, authentication flows, and storage mechanisms.
    • For example, if you store credential_id in a database or use different APIs for managing public key credentials, you can adapt the Relying Party accordingly.
  4. Key Considerations:

    • Ensure that the custom Relying Party's API endpoints handle the WebAuthn protocol correctly, following FIDO2 standards.
    • Security is paramount when handling credentials and tokens, so the custom Relying Party should use secure communication protocols (e.g., HTTPS) and implement proper token management (e.g., JWT expiration handling).


Summary

By default, the WebAuthnClient uses a built-in Relying Party to manage credential storage and verification. However, if you need more control or have a custom backend infrastructure, you can pass in your own Relying Party implementation, giving you flexibility to integrate FIDO2 authentication into any system. This modular approach ensures that developers can easily adopt WebAuthn while maintaining full control over server-side processes.

Working with React Native Applications

This section will focus on integration of the ZSM Client SDK into React Native-based applications.

Requirements

ZSM's React Native support extends to version 0.76 and later. This is required to support both the latest versions of iOS v.18 and Android v.7.0 (minSdk 24).

React Native apps may target iOS 15.1+ and Android 6.0+ (API 23+) or newer.

Note: that if you need to support older versions of iOS or Android, the ZSM Client SDK very well may support it as well, though we are no longer engaging in active development for these versions.

You may use Windows, macOS, or Linux as your development operating system, though building and running iOS apps is limited to macOS (note: tools like Expo SDK v49+ can be used to work around this).

Example React Native Project Files

Example implementations are included in the ZSM Client SDK in the folder examples.

Installation & Setup for React Native Applications

The ZSM Client SDK provides programmatic access to Ideem's FIDO2 Authentication functionality. This guide walks you through installing and configuring the SDK in a React Native project.

Step 1: Install the NPM Package

Run the following command from your project directory to install the ZSM Client SDK:

npm install @ideem/zsm-react-native --save

After installation, verify that your package.json includes (#.#.## will depend on the version installed):

"dependencies": {
    "@ideem/zsm-react-native": "^#.#.##"
}

Step 2: Import the ZSM Client SDK

Import the required client from the ZSM Client SDK into your React Native application:

FIDO2 Client:

import { FIDO2Client } from '@ideem/zsm-react-native';

Step 3: Set Up the Configuration File

Create a JSON configuration file or define a configuration object within your application. It should contain the following properties:

{
    "application_id": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
    "host_url": "https://zsm-authenticator-demo.useideem.com/",
    "application_environment": "TEST",
    "api_key": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
}

Configuration Properties

Property NameData TypeDescriptionExample Value
application_idstringUnique application identifier provided by Ideem.123e4567-e89b-12d3-a456-426614174000
host_urlstringURL of the region-specific ZSM server provided by Ideem.https://zsm-authenticator-demo.useideem.com/
application_environmentstringEnvironment setting (TEST or PRODUCTION).TEST
api_keystringAPI key for authentication, provided by Ideem.33214443-c760-4f8e-924e-9a2ad5cb0bf6

These values will be provided by Ideem. Sample configurations for testing environments are included in the SDK's examples.


Step 4: Initialize the SDK

After importing the SDK and setting up the configuration file, initialize the client with the configuration object:

FIDO2 Client Initialization:

const client = new FIDO2Client(config);

Pass the config object defined in Step 3 into the initialization. This connects your application to the ZSM services using your credentials.


FIDO2 APIs for React Native Applications

Ideem's FIDO2Client provides an abstraction for integrating with WebAuthn and FIDO2 authentication in your React Native application. It simplifies managing interactions with a Relying Party (RP), handling user enrollment, and verifying authentication challenges.

The FIDO2Client handles:

  • Checking if a user is enrolled (linked to a cryptographically bound account).
  • Creating new credentials (user enrollment).
  • Verifying existing credentials during authentication.
  • Supporting step-up authentication for sensitive operations.

This document details the core methods and best practices for using the FIDO2Client.


Relying Party Overview

A Relying Party (RP) is a server or service that initiates WebAuthn-based authentication. The RP generates cryptographic challenges for user registration or login and verifies the returned signatures using stored credentials.

The steps typically involve:

  1. Registration: The RP generates a challenge and sends it to the user’s authenticator. Once the credential is created, the RP stores the credential ID and public key for future use.
  2. Authentication: The RP sends a challenge to the user's authenticator, receives a signed response, and verifies it using the associated public key.

The FIDO2Client abstracts these steps into simple methods, letting developers focus on integration.


Interface Definitions

Before proceeding, ensure you have imported the FIDO2Client from the ZSM React Native SDK:

import { FIDO2Client } from '@ideem/zsm-react-native';

Webauthn Retrieve: FIDO2Client.webauthnRetrieve()

This method retrieves the WebAuthn credential for a user, enabling the Relying Party to verify their enrollment status.

Parameters

Parameter NameData TypeDescription
usernamestringThe username or identifier for the user.

Returns

Parameter NameData TypeDescription
responsePublicKeyCredentialContains the user’s WebAuthn attestation data.

Usage Example

client
  .webauthnRetrieve('exampleuser')
  .then((credential) => {
    console.log('Credential retrieved:', credential);
  })
  .catch((error) => {
    console.error('Error retrieving credential:', error.message);
  });

Webauthn Create: FIDO2Client.webauthnCreate()

This method registers a new WebAuthn credential for the user. It generates a key pair and securely binds the private key to the user and their device.

Parameters

Parameter NameData TypeDescription
usernamestringThe username or identifier for the user.

Returns

Parameter NameData TypeDescription
credentialPublicKeyCredentialThe newly created WebAuthn credential object.

Usage Example

client
  .webauthnCreate('exampleuser')
  .then((credential) => {
    console.log('Credential created successfully:', credential);
  })
  .catch((error) => {
    console.error('Error creating credential:', error.message);
  });

Webauthn Get: FIDO2Client.webauthnGet()

This method authenticates a user by requesting their authenticator to sign a cryptographic challenge. The Relying Party verifies the signed response using the stored public key.

Parameters

Parameter NameData TypeDescription
usernamestringThe username or identifier for the user.

Returns

Parameter NameData TypeDescription
assertionPublicKeyCredentialThe signed WebAuthn credential assertion object.

Usage Example

client
  .webauthnGet('exampleuser')
  .then((result) => {
    console.log('Authentication successful:', result);
  })
  .catch((error) => {
    console.error('Error during authentication:', error.message);
  });

Example Code

Example of Default Flow: Registration and Authentication

Here’s a complete flow using the default Relying Party:

const client = new FIDO2Client(config);

const username = 'exampleuser';

// Check if the user is enrolled, and if not, create a credential
client
  .checkIdentity(username, true)
  .then(() => {
    console.log('Identity check complete');
    return client.webauthnCreate(username);
  })
  .then((credential) => {
    console.log('Credential created successfully:', credential);
    return client.webauthnGet(username);
  })
  .then((result) => {
    console.log('Authentication successful:', result);
  })
  .catch((error) => {
    console.error('Error in flow:', error.message);
  });

Custom Relying Party Example

If you need more control, create a custom Relying Party to handle credential storage and management:

class CustomRelyingParty {
  constructor(apiHost) {
    this.apiHost = apiHost;
  }

  async startRegistration(userId) {
    const response = await fetch(`${this.apiHost}/registration/start`, {
      method: 'POST',
      body: JSON.stringify({ userId }),
    });
    return response.json();
  }

  async finishRegistration(userId, credential) {
    const response = await fetch(`${this.apiHost}/registration/finish`, {
      method: 'POST',
      body: JSON.stringify({ userId, credential }),
    });
    return response.json();
  }
}

const customRelyingParty = new CustomRelyingParty('https://custom-rp.example.com');
const client = new FIDO2Client({ relyingParty: customRelyingParty });

client
  .checkIdentity('exampleuser', true)
  .then(() => console.log('Identity verified'))
  .catch((error) => console.error('Error verifying identity:', error.message));

Explanation

The FIDO2Client simplifies the integration of FIDO2 and WebAuthn by abstracting complex interactions with authenticators and Relying Parties. Below is a breakdown of how its key features work together:

  1. Checking Identity:

    • The checkIdentity method ensures that the user's identity is either already registered or creates a new one if necessary. This serves as the first step in establishing a secure association between the user and the application.
  2. Creating Credentials:

    • Using webauthnCreate, the client generates a new cryptographic credential for the user. This step involves securely binding the credential to the user’s device, ensuring the private key never leaves the authenticator.
  3. Retrieving Credentials:

    • The webauthnRetrieve method allows the client to fetch stored credentials linked to the user. This is critical for verifying enrollment and determining the appropriate next step in the authentication process.
  4. Authentication:

    • The webauthnGet method facilitates secure user authentication by leveraging the stored credential. The authenticator signs a cryptographic challenge, which is verified by the Relying Party to confirm the user’s identity.
  5. Relying Party Abstraction:

    • The FIDO2Client works seamlessly with a default Relying Party setup but also allows for custom Relying Party implementations. This flexibility ensures the SDK can adapt to various backend architectures.
  6. Security and Compliance:

    • By adhering to FIDO2 and WebAuthn standards, the client ensures secure and phishing-resistant authentication. Developers can integrate these advanced security features without needing deep expertise in cryptography or authentication protocols.

By following the default flow or implementing a custom Relying Party, developers can build robust, secure authentication workflows with minimal effort.


Summary

The FIDO2Client provides a simple and flexible way to integrate WebAuthn into your React Native applications. Its methods for credential management and authentication abstract the complexities of the FIDO2/WebAuthn standard, letting you focus on building secure user experiences.

For advanced use cases, such as custom Relying Party integration, the FIDO2Client offers extensibility while adhering to FIDO2 security standards.

Working with Android Applications

Adding the ZSM Client SDK to your Android project using Android Studio

System Requirements

  • Android Phone
  • AndroidOS 8 (API Level 26) and newer

Languages Supported

The following languages are supported by the ZSM Client SDK for Android development:

  • Kotlin build 1.9.0 and newer
  • Java 8 and newer

Tool Support

  • Android Studio 3.1 and newer

Example Android Project Files

Example client app project files are included with the SDK along with sample code. They can be found in the examples folder of the SDK package:

  • UMFA Kotlin: examples/umfa_kotlin
    This is an example Universal MFA Android application written in Kotlin. It provides example use of the UMFAClient APIs: checkEnrollment, enroll, and authenticate.

  • UMFA Java: examples/umfa_java
    This is an example Universal MFA Android application written in Java. It provides example use of the UMFAClient APIs: checkEnrollment, enroll, and authenticate.

  • FIDO2 Kotlin: examples/fido2_kotlin
    This is an example FIDO2 Auth Android application written in Kotlin. It provides example use of the FIDO2Client APIs: webauthnRetrieve, webauthnCreate, and webauthnGet.

  • FIDO2 Java: examples/fido2_java
    This is an example FIDO2 Auth Android application written in Java. It provides example use of the FIDO2Client APIs: webauthnRetrieve, webauthnCreate, and webauthnGet.

Setup for Native Android Applications

Adding the ZSM Client SDK to your Android project

Note: The sample applications can be built to either a physical Android phone or to a virtual device using the Android Studio Emulator. In either case, you must set up biometric authentication on the device. The Emulator provides a way to simulate biometric authentication.

Integration Steps

Step #1: Open Android Studio

Step #2: Create a new Project
Select from the available templates, or choose “Blank” to start an empty project from scratch.

Create Project

(NOTE: If working from an existing project, skip ahead to step 5.)

Step #3: Name the Project
Choose any name you would like and pick a folder you wish to save the project to. In this case, we will be calling it "Sample ZSM Integration" and scoping it to the “com.useideem.zsmclient.sample” namespace.

Step #4: Select the Programming Language You Wish to Use
Either Java or Kotlin.

Step #5: Select a Minimum Target Architecture
Choose the minimum target architecture and then click the Finish button. Keep in mind, the device architectures you intend to target will impact the set of features available to you (including biometrics). Be sure to be aware of your project's specific needs.

The ZSM Client SDK leverages CMake to produce a shared object (.so) to communicate with the ZSM Module and is designed to be universally compatible with the most number of platforms and devices as possible.

Although, selecting an API version below 23 could result in device limitations in functionality.

Step #6: Add the Library to the Project
Open the Import Module dialog, accessed by clicking File > New > Import Module. The Import Module From Source dialog box will open.

Step #7: Select the Source Directory of the SDK
Ensure the Import checkbox is selected. Provide a name for the module (or leave the default suggestion in place). Then, click the Finish button.

Step #8: Specify the necessary plugins and dependencies in your Gradle file

Java Projects
For Java projects, the following plugins and depdencencies are required:

plugins {
    id 'com.android.application'
}

dependencies {
    implementation(files("../libs/ZSM.aar"))
}

Where the path to the ZSM.aar file is appropriate for your specific project structure. For an example, reference the build.gradle file provided in the example Java applications included with the SDK.

Kotlin Projects
For Kotlin projects, the following plugins and depdendencies are required:

plugins {
    id("com.android.application")
    id("org.jetbrains.kotlin.android")
}

dependencies {
    implementation(files("../libs/ZSM.aar"))
}

Where the path to the ZSM.aar file is appropriate for your specific project structure. For an example, reference the build.gradle.kts file provided in the example Kotlin applications included with the SDK.

Debugging & API Documentation

Debug Library

This SDK distribution also includes a debug version of the ZSM library (ZSM-debug.aar). This can be a valuable tool for local development and testing, as it includes helpful logs and debug symbols. The debug library SHOULD NOT but be used in a production deployment. An approach like the following can be setup in gradle for alternating between debug and release builds of the AAR:

  • debugImplementation files('libs/ZSM-debug.aar')
  • releaseImplementation files('libs/ZSM.aar')

IDE API Documentation

This SDK distribution also includes a zsm-javadoc.jar file that contains inline documentation for the SDK. This can be used to allow your IDE to show API descriptions and usage hints during development. It's optional and does not affect runtime behavior.

Here are the steps to use zsm-javadoc.jar in debug mode within Android Studio:

  • Open Project Structure (File > Project Structure or Cmd/Ctrl + ;)
  • Go to the Modules > Dependencies tab
  • Find the ZSM-debug.aar entry
  • Click the pencil/edit icon ✏️ to edit the library
  • In the dialog, click the “+” button next to “JavaDoc” and choose the zsm-javadoc.jar file

Android Initialization

Jump to: Kotlin, Java

Initialize a FIDO2Client instance from the ZSM module by creating an instance of the ZSMConfig class with the necessary configuration parameters such as host_url, application_id, and consumer_id. Then, use the FIDO2Client initializer to create the instance, which is required for performing all FIDO2 Auth operations.

Custom logging can be defined when initializing the FIDO2Client object. If a custom logging function is not provided, a default logging method is used. This method uses Android's built-in logging methods and maps to the LogLevel enum defined within the API.

Kotlin

Usage

 private fun initializeZSM() {
        val config = ZSMConfig(JSONObject().apply {
            put("host_url", hostUrl.value)
            put("application_id", applicationId.value)
            put("consumer_id", consumerId.value)

            logLevel = LogLevel.TRACE // Set the lowest level of logging
            logging = { _, message ->
                Log.d("Custom log", message)
            }
        })

        val client = FIDO2Client(context, config)
    }

Returns

The initialized FIDO2Client instance.

Configuration Parameters

Initialize the ZSMConfig object with the required configuration.

Parameters

Parameter NameData TypeDescriptionDefault Value
host_urlStringThe URL of the ZSM server.Required
application_idStringThe unique application identifier.Required
application_environmentStringThe environment name (e.g., "TEST", "PROD").Required, "TEST"
consumer_idStringThe consumer identifier.Required
authentication_hostStringAuthentication service host URL (if different from host_url).Same as host_url
headersJSONObject?Headers used while performing remote transactions.null
metadataJSONObject?Metadata provided with the request.null
request_timeout_msUIntNetwork timeout while performing remote transactions (in milliseconds).30000u
retry_countUIntNumber of retries for network transactions.0u
perform_network_health_checkBooleanWhether to perform a health check prior to instantiation.false
log_levelLogLevelThe logging level for the API..DEBUG
mpc_algorithmMPCAlgorithmThe encryption algorithm for transactions..ECDSAP256
requires_biometricsBooleanWhether to require biometrics (assumes implementation outside the API).true
logging(LogLevel, String) -> Unit)?A callback function for custom log handling.null

Configuring Logging

The ZSM SDK provides flexible logging configuration options. You can set the log level and provide a custom logging implementation to route log messages to your application's logging infrastructure.

Setting Log Level

You can set the log level either during initial configuration or after creating the ZSMConfig object:

// Option 1: During initialization
val config = ZSMConfig(JSONObject().apply {
    put("host_url", hostUrl)
    put("application_id", applicationId)
    put("consumer_id", consumerId)
    // Set log level directly in the config
    put("log_level", "TRACE")
})

// Option 2: After initialization
config.logLevel = LogLevel.TRACE

Custom Logging Implementation

You can provide a custom logging function that receives both the log level and message. This allows you to integrate with your application's logging infrastructure:

// Set custom logging function
config.logging = { level, message ->
    // Format the log message as needed
    val formattedMessage = "$level - $message"
    
    // Route to your logging system
    when (level) {
        LogLevel.TRACE -> Log.v("ZSM", formattedMessage)
        LogLevel.DEBUG -> Log.d("ZSM", formattedMessage)
        LogLevel.INFO -> Log.i("ZSM", formattedMessage)
        LogLevel.WARN -> Log.w("ZSM", formattedMessage)
        LogLevel.ERROR, LogLevel.FATAL -> Log.e("ZSM", formattedMessage)
    }
}

The logging function is called with two parameters:

  • level: A LogLevel enum value indicating the severity
  • message: The log message as a String

Log Levels

enum class LogLevel(val value: Int) {
    TRACE(-1),
    DEBUG(0),
    INFO(1),
    WARN(2),
    ERROR(3),
    FATAL(4)
}
LevelDescription
TRACEUsed for debugging purposes. This level of logging provides the most granular information at the lowest detailed level and includes network round trips.
DEBUGUsed for debugging purposes. This reveals timing information at a general level.
INFOUsed to record informational messages that highlight the progress of the application at a high level.
WARNIndicates potentially harmful situations.
ERRORUsed to record error events that might still allow the application to continue running.
FATALRecords very severe error events that will presumably lead the application to abort.

Returns

The initialized ZSMConfig object.

Java

The Java-friendly API allows the methods to be called using lambdas for seamless integration.

Usage

ZSMConfig config = new ZSMConfig(new JSONObject()
                    .put("host_url", this.getHostUrl())
                    .put("application_id", "########-####-####-####-############")
                    .put("consumer_id", this.getConsumerId())
            );

config.setLogLevel(LogLevel.TRACE); // Set the lowest level of logging
config.setLogging((level, message) -> {
    Log.d("Custom log", message);
});

FIDO2Client client = new FIDO2Client(context, config);

Returns

The initialized FIDO2Client instance.

ZSMConfig Properties

PropertyTypeDescriptionDefault Value
host_urlStringThe URL of the ZSM server.Required
application_idStringUnique application identifierRequired
application_environmentStringThe environment name (e.g., "TEST", "PROD").Required, "TEST"
consumer_idStringThe consumer identifier.Required
authentication_hostStringAuthentication service host URL (if different from host_url).Same as host_url
headersJSONObject?Headers used while performing remote transactions.null
metadataJSONObject?Metadata provided with the request.null
request_timeout_msintNetwork timeout while performing remote transactions (in milliseconds).30000
retry_countintNumber of retries for network transactions.0
perform_network_health_checkbooleanWhether to perform a health check prior to instantiation.false
log_levelLogLevelThe logging level for the API.LogLevel.DEBUG
mpc_algorithmMPCAlgorithmThe encryption algorithm for transactions.MPCAlgorithm.ECDSAP256
requires_biometricsbooleanWhether to require biometrics (assumes implementation outside the API).true
loggingBiConsumer<LogLevel, String>A callback function for custom log handling.null

Configuring Logging

The ZSM SDK provides flexible logging configuration options. You can set the log level and provide a custom logging implementation to route log messages to your application's logging infrastructure.

Setting Log Level

You can set the log level either during initial configuration or after creating the ZSMConfig object:

// Option 1: During initialization
JSONObject configJson = new JSONObject()
    .put("host_url", hostUrl)
    .put("application_id", applicationId)
    .put("consumer_id", consumerId)
    // Set log level directly in the config
    .put("log_level", "TRACE");

ZSMConfig config = new ZSMConfig(configJson);

// Option 2: After initialization
config.setLogLevel(LogLevel.TRACE);

Custom Logging Implementation

You can provide a custom logging function that receives both the log level and message. This allows you to integrate with your application's logging infrastructure:

// Set custom logging function
config.setLogging((level, message) -> {
    // Format the log message as needed
    String formattedMessage = level + " - " + message;
    
    // Route to your logging system
    switch (level) {
        case TRACE:
            Log.v("ZSM", formattedMessage);
            break;
        case DEBUG:
            Log.d("ZSM", formattedMessage);
            break;
        case INFO:
            Log.i("ZSM", formattedMessage);
            break;
        case WARN:
            Log.w("ZSM", formattedMessage);
            break;
        case ERROR:
        case FATAL:
            Log.e("ZSM", formattedMessage);
            break;
    }
});

The logging function is called with two parameters:

  • level: A LogLevel enum value indicating the severity
  • message: The log message as a String

Log Levels

enum LogLevel {
    TRACE(-1),
    DEBUG(0),
    INFO(1),
    WARN(2),
    ERROR(3),
    FATAL(4);
}
LevelDescription
TRACEUsed for debugging purposes. This level of logging provides the most granular information at the lowest detailed level and includes network round trips.
DEBUGUsed for debugging purposes. This reveals timing information at a general level.
INFOUsed to record informational messages that highlight the progress of the application at a high level.
WARNIndicates potentially harmful situations.
ERRORUsed to record error events that might still allow the application to continue running.
FATALRecords very severe error events that will presumably lead the application to abort.

Returns

The initialized ZSMConfig object.

FIDO2 APIs for Native Android Applications

Ideem's FIDO2 Authenticator interfaces can be used to integrate with an existing Relying Party infrastructure. A Relying Party server is responsible for managing the storage of credential_ids and public keys associated with enrollments, generating challenges, and verifying signed challenges.

These interfaces allow you to determine if a user has already been enrolled (cryptographically bound to the device), create an enrollment if they have not, or verify them. FIDO2 Authenticator WebAuthn functions can be used to provide a silent second factor after strong authentication, as well as reverification when needed for transactions requiring step up authentication.

Interface Definitions

Jump to: Kotlin, Java

Getting the version number of the SDK library: FIDO2Client.versionString

To retrieve the version number of the SDK library use the class property FIDO2Client.versionString. It will return the version number in semantic versioning format, major.minor.patch.

Kotlin

Retrieving Enrollment Status: FIDO2Client.webauthnRetrieve()

There are two versions of this method: one for retrieving credentials for the current user, and another for retrieving credentials for a specific user.

For Current User

The webauthnRetrieve method checks if the current user has previously registered credentials on this device and retrieves the enrollment status.

Usage

client.webauthnRetrieve { response ->
    if (response != null) {
        val rawId = response.getString("rawId")
        // Handle retrieved attestation data
    } else {
        Log.e("FIDO2ClientViewModel", "Error retrieving attestation data")
    }
}

Parameters

Parameter NameData TypeDescription
completion(JSONObject?) -> UnitA callback function that handles the completion of the retrieval.

Returns

The callback function returns the following parameter:

Parameter NameData TypeDescription
responseJSONObject?The retrieved enrollment status (attestation data) as a JSON object, or null if not found.
For Specific User

The webauthnRetrieve method with a user parameter checks if a specific user has previously registered credentials on this device and retrieves the enrollment status.

Usage

val userId = "user123" // Unique identifier for the user
client.webauthnRetrieve(userId) { response ->
    if (response != null) {
        val rawId = response.getString("rawId")
        // Handle retrieved attestation data for specific user
    } else {
        Log.e("FIDO2ClientViewModel", "Error retrieving attestation data for user: $userId")
    }
}

Parameters

Parameter NameData TypeDescription
userStringThe user ID for which to retrieve credentials.
completion(JSONObject?) -> UnitA callback function that handles the completion of the retrieval.

Returns

The callback function returns the following parameter:

Parameter NameData TypeDescription
responseJSONObject?The retrieved enrollment status (attestation data) as a JSON object, or null if not found.

Enrolling (Attestation): FIDO2Client.webauthnCreate()

The webauthnCreate method initiates the creation of a new credential object using the specified PublicKeyCredentialCreationOptions. The generated credential object can be stored securely for future authentication.

The response follows the PublicKeyCredential format from the WebAuthn standard.

Refer to Mozilla's online documentation on PublicKeyCredentialCreationOptions or to the W3C standard Options for Credential Creation. For response format, see the W3C standard PublicKeyCredential interface.

Usage

client.webauthnCreate(optionsJsonObject) { result, metadata, error ->
    if (result != null) {
        val rawId = result.getString("rawId")
        // Handle successful creation, store or use the rawId
    } else if (error != null) {
        Log.e("FIDO2ClientViewModel", "Error during creation: ${error.localizedMessage}")
    }
}

Parameters

Parameter NameData TypeDescription
optionsJSONObjectA JSON object representing PublicKeyCredentialCreationOptions.
completion(JSONObject?, Map<String, String>?, ZSMError?) -> UnitA callback function that handles the completion of the operation.

Returns

The callback function returns the following parameters:

Parameter NameData TypeDescription
resultJSONObject?The attestation data generated during credential creation as a JSON object.
metadataMap<String, String>?Additional metadata associated with the creation process.
errorZSMError?Error object in case of failure; otherwise, null.

Verifying (Assertion): FIDO2Client.webauthnGet()

The webauthnGet method retrieves a credential object based on the specified PublicKeyCredentialRequestOptions. This object can be used to authenticate the user.

The response follows the AuthenticatorAssertionResponse format from the WebAuthn standard.

Refer to Mozilla's online documentation on PublicKeyCredentialRequestOptions or to the W3C standard Options for Assertion Generation. For response format, see the W3C standard AuthenticatorAssertionResponse interface.

Usage

client.webauthnGet(optionsJsonObject) { result, metadata, error ->
    if (result != null) {
        // Handle successful assertion
    } else if (error != null) {
        Log.e("FIDO2ClientViewModel", "Error during assertion: ${error.localizedMessage}")
    }
}

Parameters

Parameter NameData TypeDescription
optionsJSONObjectA JSON object representing PublicKeyCredentialRequestOptions.
completion(JSONObject?, Map<String, String>?, ZSMError?) -> UnitA callback function that handles the completion of the operation.

Returns

The callback function returns the following parameters:

Parameter NameData TypeDescription
resultJSONObject?The assertion data generated during credential verification as a JSON object.
metadataMap<String, String>?Additional metadata associated with the request process.
errorZSMError?Error object in case of failure; otherwise, null.

Unbind: FIDO2Client.unbind()

There are two versions of this method: one for removing all FIDO2 credentials for the current user, and another for removing credentials for a specific user.

For Current User

The unbind method removes all FIDO2 credentials and state for the current user from the device.

Usage

client.unbind { success ->
    if (success) {
        Log.d("FIDO2ClientViewModel", "Successfully unbind FIDO2 state for current user")
    } else {
        Log.e("FIDO2ClientViewModel", "Failed to unbind FIDO2 state")
    }
}

Parameters

Parameter NameData TypeDescription
completion(Boolean) -> UnitA callback function that handles the completion of the unbind operation.

Returns

The callback function returns the following parameter:

Parameter NameData TypeDescription
successBooleanIndicates whether the unbind operation was successful.
For Specific User

The unbind method with a user parameter removes FIDO2 credentials and state for a specific user from the device.

Usage

val userId = "user123" // Unique identifier for the user
client.unbind(userId) { success ->
    if (success) {
        Log.d("FIDO2ClientViewModel", "Successfully unbind FIDO2 state for user: $userId")
    } else {
        Log.e("FIDO2ClientViewModel", "Failed to unbind FIDO2 state for user: $userId")
    }
}

Parameters

Parameter NameData TypeDescription
userStringThe user ID for which to remove credentials.
completion(Boolean) -> UnitA callback function that handles the completion of the unbind operation.

Returns

The callback function returns the following parameter:

Parameter NameData TypeDescription
successBooleanIndicates whether the unbind operation was successful.

Java

Retrieving Enrollment Status: FIDO2Client.webauthnRetrieve()

There are two versions of this method: one for retrieving credentials for the current user, and another for retrieving credentials for a specific user.

For Current User

The webauthnRetrieve method checks if the current user has previously registered credentials on this device and retrieves the enrollment status.

Usage

client.webauthnRetrieve(response -> {
    if (response != null) {
        try {
            String rawId = response.getString("rawId");
            // Handle retrieved attestation data
        } catch (JSONException e) {
            Log.e("FIDO2ClientViewModel", "Error parsing JSON response: " + e.getMessage());
        }
    } else {
        Log.e("FIDO2ClientViewModel", "Error retrieving attestation data");
    }
});

Parameters

Parameter NameData TypeDescription
completionWebAuthnRetrieveCompletionHandlerA callback interface that handles the completion of the retrieval.

The WebAuthnRetrieveCompletionHandler interface has a single method:

void onComplete(JSONObject result);

Returns

The callback function returns the following parameter:

Parameter NameData TypeDescription
resultJSONObject?The retrieved enrollment status (attestation data) as a JSON object, or null if not found.
For Specific User

The webauthnRetrieve method with a user parameter checks if a specific user has previously registered credentials on this device and retrieves the enrollment status.

Usage

String userId = "user123"; // Unique identifier for the user
client.webauthnRetrieve(userId, response -> {
    if (response != null) {
        try {
            String rawId = response.getString("rawId");
            // Handle retrieved attestation data for specific user
        } catch (JSONException e) {
            Log.e("FIDO2ClientViewModel", "Error parsing JSON response: " + e.getMessage());
        }
    } else {
        Log.e("FIDO2ClientViewModel", "Error retrieving attestation data for user: " + userId);
    }
});

Parameters

Parameter NameData TypeDescription
userStringThe user ID for which to retrieve credentials.
completionWebAuthnRetrieveCompletionHandlerA callback interface that handles the completion of the retrieval.

Returns

The callback function returns the following parameter:

Parameter NameData TypeDescription
resultJSONObject?The retrieved enrollment status (attestation data) as a JSON object, or null if not found.

Enrolling (Attestation): FIDO2Client.webauthnCreate()

The webauthnCreate method initiates the creation of a new credential object using the specified PublicKeyCredentialCreationOptions. The generated credential object can be stored securely for future authentication.

Refer to Mozilla's PublicKeyCredentialCreationOptions documentation or the W3C Options for Credential Creation.

Usage

client.webauthnCreate(optionsJsonObject, (result, metadata, error) -> {
    if (result != null) {
        try {
            String rawId = result.getString("rawId");
            // Handle successful creation, store or use the rawId
        } catch (JSONException e) {
            Log.e("FIDO2ClientViewModel", "Error parsing JSON response: " + e.getMessage());
        }
    } else if (error != null) {
        Log.e("FIDO2ClientViewModel", "Error during creation: " + error.getLocalizedMessage());
    }
});

Parameters

Parameter NameData TypeDescription
optionsJSONObjectA JSON object representing PublicKeyCredentialCreationOptions.
completionWebAuthnCompletionHandlerA callback interface that handles the completion of the operation.

The WebAuthnCompletionHandler interface has a single method:

void onComplete(JSONObject result, Map<String, String> metadata, ZSMError error);

Returns

The callback function returns the following parameters:

Parameter NameData TypeDescription
resultJSONObject?The attestation data generated during credential creation as a JSON object.
metadataMap<String, String>?Additional metadata associated with the creation process.
errorZSMError?Error object in case of failure; otherwise, null.

Verifying (Assertion): FIDO2Client.webauthnGet()

The webauthnGet method retrieves a credential object based on the specified PublicKeyCredentialRequestOptions. This object can be used to authenticate the user.

Refer to Mozilla's PublicKeyCredentialRequestOptions documentation or the W3C Options for Assertion Generation.

Usage

client.webauthnGet(optionsJsonObject, (result, metadata, error) -> {
    if (result != null) {
        // Handle successful assertion
    } else if (error != null) {
        Log.e("FIDO2ClientViewModel", "Error during assertion: " + error.getLocalizedMessage());
    }
});

Parameters

Parameter NameData TypeDescription
optionsJSONObjectA JSON object representing PublicKeyCredentialRequestOptions.
completionWebAuthnCompletionHandlerA callback interface that handles the completion of the operation.

Returns

The callback function returns the following parameters:

Parameter NameData TypeDescription
resultJSONObject?The assertion data generated during credential verification as a JSON object.
metadataMap<String, String>?Additional metadata associated with the request process.
errorZSMError?Error object in case of failure; otherwise, null.

Unbind: FIDO2Client.unbind()

There are two versions of this method: one for removing all FIDO2 credentials for the current user, and another for removing credentials for a specific user.

For Current User

The unbind method removes all FIDO2 credentials and state for the current user from the device.

Usage

client.unbind(success -> {
    if (success) {
        Log.d("FIDO2ClientViewModel", "Successfully unbound FIDO2 state for current user");
    } else {
        Log.e("FIDO2ClientViewModel", "Failed to unbind FIDO2 state");
    }
});

Parameters

Parameter NameData TypeDescription
completionBooleanCompletionHandlerA callback interface that handles the completion of the unbind operation.

The BooleanCompletionHandler interface has a single method:

void onComplete(boolean success);

Returns

The callback function returns the following parameter:

Parameter NameData TypeDescription
successbooleanIndicates whether the unbind operation was successful.
For Specific User

The unbind method with a user parameter removes FIDO2 credentials and state for a specific user from the device.

Usage

String userId = "user123"; // Unique identifier for the user
client.unbind(userId, success -> {
    if (success) {
        Log.d("FIDO2ClientViewModel", "Successfully unbound FIDO2 state for user: " + userId);
    } else {
        Log.e("FIDO2ClientViewModel", "Failed to unbind FIDO2 state for user: " + userId);
    }
});

Parameters

Parameter NameData TypeDescription
userStringThe user ID for which to remove credentials.
completionBooleanCompletionHandlerA callback interface that handles the completion of the unbind operation.

Returns

The callback function returns the following parameter:

Parameter NameData TypeDescription
successbooleanIndicates whether the unbind operation was successful.

Working with iOS Applications

Adding the ZSM Client SDK to your iOS project using Xcode

System Requirements

  • Apple iPhone 5s and newer
  • Apple iOS 11 and newer

Languages Supported

The following languages are supported by the Client SDK for iOS development:

  • Swift 4 and newer
  • Objective-C (set by the version of CLANG supported by Xcode 9)

Tool Support

  • Xcode 9 and newer

Example iOS Project Files

Example client app project files are included with the SDK along with sample code. They can be found in the examples folder of the SDK package:

  • UMFA Swift: examples/umfa_swift
    This is an example Universal MFA iOS application written in Swift. It provides example use of the UMFAClient APIs: checkEnrollment, enroll, and authenticate.

  • UMFA Objective-C: examples/umfa_objc
    This is an example Universal MFA iOS application written in Objective-C. It provides example use of the UMFAClient APIs: checkEnrollment, enroll, and authenticate.

  • FIDO2 Swift: examples/fido2_swift
    This is an example FIDO2 Auth iOS application written in Swift. It includes provides example use of the FIDO2Client APIs: webauthnRetrieve, webauthnCreate, and webauthnGet.

  • FIDO2 Objective-C: examples/fido2_objc
    This is an example FIDO2 Auth iOS application written in Objective-C. It includes provides example use of the FIDO2Client APIs: webauthnRetrieve, webauthnCreate, and webauthnGet.

Setup for Native iOS Applications

Adding the ZSM Client SDK to your iOS project

Note: The sample application must be built to a physical iPhone due to limitations of the Xcode Simulator.

Step #1: Open Xcode

Step #2: Create a new Project
Select the topmost option from the quick launch menu. (NOTE: If working from an existing project, skip ahead to step 6.)

New Project

Step #3: Select a Platform and Template
In this case, we will prepare the project as an App intended to be run on the iOS platform. After making your selections, click the Next button to proceed.

Step #4: Name the Project
Choose any name you would like. Then, select your team (note that this is needed to perform a full build after adding the ZSM Client SDK to the project for it to function for testing purposes. Add your organization's name, and finally select the language you wish to employ. We'll be using Swift for the purposes of this example). Click the Next button.

Step #5: Decide Where You Would Like to Save the Project
Once you navigate to your desired save location in the Finder dialog, click Finish.

Step #6: Add the Framework to the Project
Right-click on the side panel, and select Add Files to “<YOUR_PROJECT>”

Browse to the folder location into which you saved the ZSM Client SDK and select the Framework directory contained therein.

Add Framework

Add Framework

Step #7: Ensure the Add to Targets Checkbox is Selected
Optionally select Copy Items (if you're creating the project in a different location, or intend to create more than one using the framework).

Step #8: Finally, Click the Add button.
Your project structure should now resemble the following:

Final Project

iOS Initialization

Jump to: Swift, Objective-C

Initialize a FIDO2Client instance from the ZSM module by creating an instance of the ZSMConfig class with the necessary configuration parameters such as host_url, application_id, and consumer_id. Then, use the FIDO2Client constructor to initialize the instance, which is required for performing all FIDO2 Auth operations.

Custom logging can be defined when initializing a FIDO2Client object. If a custom logging function is not provided, a default logging method is used. This method uses iOS's built-in logging methods and maps to the LogLevel enum defined within the API.

Swift

Initialization

Usage

func initializeFIDO2Client() {
        let config = ZSMConfig(json: [
            "host_url": hostUrl,
            "application_id": applicationId,
            "application_environment": "TEST",
            "consumer_id": consumerId
        ])

        config.logLevel = .Debug
        config.logFunction = { level, message in
            print("[\(level)] \(message)")
        }
        let client = FIDO2Client(config)
    }

Returns The initialized FIDO2Client instance.

Configuration Parameters

Initialize the ZSMConfig object with the required configuration.

Parameters

Parameter NameData TypeDescriptionDefault Value
host_urlNSURLThe URL of the ZSM server.Required
application_idNSStringThe environment name (e.g., "TEST", "PROD").Required
consumer_idNSStringThe consumer identifier.Required
application_environmentNSStringThe environment name (e.g., "TEST", "PROD").Required, "TEST"
request_timeout_msNSUIntegerNetwork timeout while performing remote transactions (in milliseconds).30000
retry_countNSUIntegerNumber of retries for network transactions.0
perform_network_health_checkBOOLWhether to perform a health check prior to instantiation.YES
headersNSDictionaryHeaders used while performing remote transactions.nil
metadataNSDictionaryMetadata used while performing remote transactions.nil
keychain_groupNSString?Shared keychain group ID for multiple applications of the same vendor.nil
mpc_algorithmMPCAlgorithmThe encryption algorithm for transactions..ECDSAP256
requires_biometricsBOOLWhether to bypass biometrics (assuming implementation outside the API).NO
logLevelLogLevelThe logging level for the API..Info
log_function(LogLevel, NSString) -> VoidA callback function for custom log handling.nil

Configuring Logging

The ZSM SDK provides flexible logging configuration options. You can set the log level and provide a custom logging implementation to route log messages to your application's logging infrastructure.

Setting Log Level

You can set the log level either during initialization or after creating the ZSMConfig object:

// Option 1: During initialization via JSON
let config = ZSMConfig(json: [
    "host_url": hostUrl,
    "application_id": applicationId,
    "consumer_id": consumerId,
    "log_level": LogLevel.trace.rawValue // Set log level in the configuration
])

// Option 2: After initialization
config.logLevel = .trace

Custom Logging Implementation

You can provide a custom logging function to capture and process log messages in your application:

// Set custom logging function
config.logFunction = { level, message in
    // Format and route logs as needed
    let formattedMessage = "[\(level)] \(message)"
    
    switch level {
    case .trace:
        os_log("%{public}@", log: .default, type: .debug, formattedMessage)
    case .debug:
        os_log("%{public}@", log: .default, type: .debug, formattedMessage)
    case .info:
        os_log("%{public}@", log: .default, type: .info, formattedMessage)
    case .warn:
        os_log("%{public}@", log: .default, type: .error, formattedMessage)
    case .error, .fatal:
        os_log("%{public}@", log: .default, type: .fault, formattedMessage)
    @unknown default:
        os_log("%{public}@", log: .default, type: .default, formattedMessage)
    }
}

The logging function is called with two parameters:

  • level: A LogLevel enum value indicating the severity
  • message: The log message as a String

You can use this callback to integrate with various logging frameworks such as:

  • Apple's unified logging system (os_log)
  • CocoaLumberjack
  • Custom logging solutions

LogLevel Enum

enum LogLevel: Int {
    case trace = -1
    case debug = 0
    case info = 1
    case warn = 2
    case error = 3
    case fatal = 4
}

LogLevel Descriptions

LevelDescription
LogLevelTraceUsed for debugging purposes. Provides the most granular information at the lowest detailed level, including network round trips.
LogLevelDebugProvides general timing information for debugging purposes.
LogLevelInfoUsed for recording informational messages that highlight the application's progress at a high level.
LogLevelWarnIndicates potentially harmful situations.
LogLevelErrorUsed for recording error events that might still allow the application to continue running.
LogLevelFatalUsed for recording severe error events that will presumably lead the application to abort.

Returns
The initialized ZSMConfig object.

Objective-C

Initialization

Usage

NSURL *hostUrl = [NSURL URLWithString:@"https://zsm-host-server-address"];
NSString *applicationId = @"########-####-####-####-############"
NSString *consumerId = @"consumer123";

ZSMConfig *config = [[ZSMConfig alloc] initWithJSON:@{@"host_url": hostUrl, @"application_id":applicationId,
@"consumer_id":consumerId}];

config.logLevel = LogLevelDebug;
config.logFunction = ^(LogLevel level, NSString *message) {
    NSLog(@"[%ld] %@", (long)level, message);
};

FIDO2Client *client = [[FIDO2Client alloc] initWithConfig:config];

Returns The initialized FIDO2Client instance.

Configuration Parameters

Initialize the ZSMConfig object with the required configuration.

Parameters

Parameter NameData TypeDescriptionDefault Value
host_urlNSURL *The URL of the ZSM server.Required
application_idNSString *Unique application identifier.Required
consumer_idNSString *The consumer identifier.Required
application_environmentNSString *The environment name (e.g., "TEST", "PROD").Required, "TEST"
request_timeout_msNSUIntegerNetwork timeout while performing remote transactions (in milliseconds).30000 (30s)
retry_countNSUIntegerNumber of retries for network transactions.0
perform_network_health_checkBOOLWhether to perform a health check prior to instantiation.YES
headersNSDictionary *Headers used while performing remote transactions.nil
metadataNSDictionary *Metadata used while performing remote transactions.nil
keychain_groupNSString *Shared keychain group ID for multiple applications of the same vendor.nil
mpc_algorithmMPCAlgorithmThe encryption algorithm for transactions..MPCAlgorithmECDSAP256
requires_biometricsBOOLWhether to bypass biometrics (assuming implementation outside the API).NO
log_levelLogLevelThe logging level for the API..LogLevelInfo
log_functionZSMLoggingCallbackA callback function for custom log handling.nil

LogLevel Enum

typedef NS_ENUM(NSInteger, LogLevel) {
    LogLevelTrace = -1,
    LogLevelDebug = 0,
    LogLevelInfo,
    LogLevelWarn,
    LogLevelError,
    LogLevelFatal
};

Configuring Logging

The ZSM SDK provides flexible logging configuration options for Objective-C applications. You can set the log level and provide a custom logging implementation to route log messages to your application's logging infrastructure.

Setting Log Level

You can set the log level either during initialization or after creating the ZSMConfig object:

// Option 1: During initialization via JSON dictionary
NSDictionary *configDict = @{
    @"host_url": hostUrlString,
    @"application_id": applicationId,
    @"consumer_id": consumerId,
    @"log_level": @(LogLevelTrace)  // Set log level in the configuration
};
ZSMConfig *config = [[ZSMConfig alloc] initWithJSON:configDict];

// Option 2: After initialization
config.logLevel = LogLevelTrace;

Custom Logging Implementation

You can provide a custom logging function to capture and process log messages in your application:

// Set custom logging function with a block
config.logFunction = ^(LogLevel level, NSString *message) {
    // Format and route logs as needed
    NSString *levelString;
    switch (level) {
        case LogLevelTrace:
            levelString = @"TRACE";
            break;
        case LogLevelDebug:
            levelString = @"DEBUG";
            break;
        case LogLevelInfo:
            levelString = @"INFO";
            break;
        case LogLevelWarn:
            levelString = @"WARN";
            break;
        case LogLevelError:
            levelString = @"ERROR";
            break;
        case LogLevelFatal:
            levelString = @"FATAL";
            break;
        default:
            levelString = @"UNKNOWN";
            break;
    }
    
    NSString *formattedMessage = [NSString stringWithFormat:@"[%@] %@", levelString, message];
    
    // Route to your logging system
    NSLog(@"%@", formattedMessage);
    
    // Or use os_log if targeting iOS 10+
    if (@available(iOS 10.0, *)) {
        os_log_with_type(OS_LOG_DEFAULT, OS_LOG_TYPE_INFO, "%{public}@", formattedMessage);
    }
};

The logging function is called with two parameters:

  • level: A LogLevel enum value indicating the severity
  • message: The log message as an NSString

You can use this callback to integrate with various logging frameworks such as:

  • NSLog (basic logging)
  • Apple's unified logging system (os_log)
  • CocoaLumberjack
  • Custom logging solutions

LogLevel Enum

typedef NS_ENUM(NSInteger, LogLevel) {
    LogLevelTrace = -1,
    LogLevelDebug = 0,
    LogLevelInfo,
    LogLevelWarn,
    LogLevelError,
    LogLevelFatal
};

LogLevel Descriptions

LevelDescription
LogLevelTraceUsed for debugging purposes. Provides the most granular information at the lowest detailed level, including network round trips.
LogLevelDebugProvides general timing information for debugging purposes.
LogLevelInfoUsed for recording informational messages that highlight the application's progress at a high level.
LogLevelWarnIndicates potentially harmful situations.
LogLevelErrorUsed for recording error events that might still allow the application to continue running.
LogLevelFatalUsed for recording severe error events that will presumably lead the application to abort.

Returns
The initialized ZSMConfig object.

FIDO2 APIs for Native iOS Applications

Ideem's FIDO2 Authenticator interfaces can be used to integrate with an existing Relying Party infrastructure, where you host the Relying Party server and manage the storage of credential_ids and public keys associated with enrollments, generate challenges, and verify signed challenges.

These interfaces allow you to determine if a user has already been enrolled (cryptographically bound to the device), create an enrollment if they have not, or verify them. FIDO2 Authenticator WebAuthn functions can be used to provide a silent second factor after strong authentication, as well as reverification when needed for transactions requiring step up authentication.

Interface Definitions

Jump to: Swift, Objective-C

Getting the version number of the SDK library: FIDO2Client.versionString

To retrieve the version number of the SDK library use the class property FIDO2Client.versionString. It will return the version number in semantic versioning format, major.minor.patch.

Swift

Retrieving Enrollment Status (Attestation): FIDO2Client.webauthnRetrieve()

There are two versions of this method: one for retrieving credentials for the current user, and another for retrieving credentials for a specific user.

For Current User

The webauthnRetrieve(completion:) method checks if the current user has previously registered credentials on this device and retrieves the enrollment status.

Usage

client.webauthnRetrieve { data, metadata, error in
    if let data = data {
        // Process attestation data
        if let rawId = data["rawId"] as? String {
            // Use the credential ID
        }
    } else if let error = error {
        // Handle error
    }
}

Parameters

Parameter NameData TypeDescription
completion([String: Any]?, [String: String]?, ZSMError?) -> VoidA callback function that handles the completion of the retrieval.

Returns
The completion handler provides the following parameters:

Parameter NameData TypeDescription
data[String: Any]?The enrollment status (attestation data) retrieved from the device as a dictionary.
metadata[String: String]?Additional metadata associated with the retrieval process.
errorZSMError?Error object in case of failure; otherwise, nil.

For Specific User

The webauthnRetrieve(forUser:completion:) method checks if a specific user has previously registered credentials on this device and retrieves the enrollment status.

Usage

let userId = "user123" // Unique identifier for the user
client.webauthnRetrieve(forUser: userId) { data, metadata, error in
    if let data = data {
        // Process attestation data for specific user
        if let rawId = data["rawId"] as? String {
            // Use the credential ID for this specific user
        }
    } else if let error = error {
        // Handle error
    }
}

Parameters

Parameter NameData TypeDescription
userStringThe user ID for which to retrieve credentials.
completion([String: Any]?, [String: String]?, ZSMError?) -> VoidA callback function that handles the completion of the retrieval.

Returns
The completion handler provides the following parameters:

Parameter NameData TypeDescription
data[String: Any]?The enrollment status (attestation data) retrieved for the specified user as a dictionary.
metadata[String: String]?Additional metadata associated with the retrieval process.
errorZSMError?Error object in case of failure; otherwise, nil.

Enrolling (Attestation): FIDO2Client.webauthnCreate()

The webauthnCreate(options:completion:) method initiates the creation of a new credential object, using the specified PublicKeyCredentialCreationOptions. The generated credential object can be stored securely for future authentication.

The response follows the PublicKeyCredential format from the WebAuthn standard.

Refer to Mozilla's online documentation on PublicKeyCredentialCreationOptions or to the W3C standard Options for Credential Creation. For response format, see the W3C standard PublicKeyCredential interface.

Usage

// Create options dictionary following FIDO2 WebAuthn standard
let options: [String: Any] = [
    "rp": [
        "id": "example.com",
        "name": "Example Service"
    ],
    "user": [
        "id": "user-unique-id-as-base64",
        "name": "username",
        "displayName": "User's Display Name"
    ],
    "challenge": "base64-encoded-challenge",
    "pubKeyCredParams": [
        ["type": "public-key", "alg": -7] // ES256
    ]
    // Additional optional parameters
]

client.webauthnCreate(options: options) { data, metadata, error in
    if let data = data {
        // Handle successful creation, access attestationObject and clientDataJSON
        if let rawId = data["rawId"] as? String {
            // Store credential ID for future authentications
        }
    } else if let error = error {
        // Handle error
    }
}

Parameters

Parameter NameData TypeDescription
options[String: Any]A dictionary representing PublicKeyCredentialCreationOptions.
completion([String: Any]?, [String: String]?, ZSMError?) -> VoidA callback function that handles the completion of the operation.

Returns
The completion handler provides the following parameters:

Parameter NameData TypeDescription
data[String: Any]?The attestation data generated during credential creation as a dictionary.
metadata[String: String]?Additional metadata associated with the creation process.
errorZSMError?Error object in case of failure; otherwise, nil.

Verifying (Assertion): FIDO2Client.webauthnGet()

The webauthnGet(options:completion:) method retrieves a credential object based on the specified PublicKeyCredentialRequestOptions. This object can be used to authenticate the user.

The response follows the AuthenticatorAssertionResponse format from the WebAuthn standard.

Refer to Mozilla's online documentation on PublicKeyCredentialRequestOptions or to the W3C standard Options for Assertion Generation. For response format, see the W3C standard AuthenticatorAssertionResponse interface.

Usage

// Create options dictionary following FIDO2 WebAuthn standard
let options: [String: Any] = [
    "challenge": "base64-encoded-challenge",
    "rpId": "example.com",
    "allowCredentials": [
        [
            "type": "public-key",
            "id": "previously-stored-credential-id"
        ]
    ],
    "timeout": 60000
]

client.webauthnGet(options: options) { data, metadata, error in
    if let data = data {
        // Handle successful assertion
        if let authenticatorData = data["authenticatorData"] as? String,
           let signature = data["signature"] as? String {
            // Verify the signature and authenticator data
        }
    } else if let error = error {
        // Handle error
    }
}

Parameters

Parameter NameData TypeDescription
options[String: Any]A dictionary representing PublicKeyCredentialRequestOptions.
completion([String: Any]?, [String: String]?, ZSMError?) -> VoidA callback function that handles the completion of the operation.

Returns
The completion handler provides the following parameters:

Parameter NameData TypeDescription
data[String: Any]?The assertion data generated during credential verification as a dictionary.
metadata[String: String]?Additional metadata associated with the request process.
errorZSMError?Error object in case of failure; otherwise, nil.

Unbinding: FIDO2Client.unbind()

There are two versions of this method: one for removing all FIDO2 credentials for the current user, and another for removing credentials for a specific user.

For Current User

The unbind() method removes all FIDO2 credentials and state for the current user from the device.

Usage

client.unbind()

Parameters
None.

Returns
None. |

For Specific User

The unbind(user:) method removes FIDO2 credentials and state for a specific user from the device.

Usage

let userId = "user123" // Unique identifier for the user
client.unbind(user: userId);

Parameters

Parameter NameData TypeDescription
userStringThe user ID for which to remove credentials.

Returns
None. |

Objective-C

Retrieving Enrollment Status (Attestation): FIDO2Client.webauthnRetrieve()

There are two versions of this method: one for retrieving credentials for the current user, and another for retrieving credentials for a specific user.

For Current User

To check if the current user has previously registered credentials on this device and retrieve the enrollment status, use the webauthnRetrieveWithCompletion: method.

Usage

[client webauthnRetrieveWithCompletion:^(NSDictionary * _Nullable data, NSDictionary<NSString *, NSString *> * _Nullable metadata, ZSMError * _Nullable error) {
    if (data) {
        // Process attestation data
    } else if (error) {
        // Handle error
    }
}];

Parameters

Parameter NameData TypeDescription
completionvoid (^)(NSDictionary * _Nullable, NSDictionary<NSString *, NSString *> * _Nullable, ZSMError * _Nullable)A callback function that handles the completion of the retrieval operation.

Returns
The callback function receives the following parameters:

Parameter NameData TypeDescription
dataNSDictionary *The enrollment status (attestation data) retrieved from the device as a dictionary.
metadataNSDictionary<NSString *, NSString *> *Additional metadata returned by the operation, if available.
errorZSMError *Error object describing any issues encountered during the retrieval process.

For Specific User

To check if a specific user has previously registered credentials on this device and retrieve the enrollment status, use the webauthnRetrieveForUser:withCompletion: method.

Usage

NSString *userId = @"user123"; // Unique identifier for the user
[client webauthnRetrieveForUser:userId withCompletion:^(NSDictionary * _Nullable data, NSDictionary<NSString *, NSString *> * _Nullable metadata, ZSMError * _Nullable error) {
    if (data) {
        // Process attestation data for specific user
    } else if (error) {
        // Handle error
    }
}];

Parameters

Parameter NameData TypeDescription
userNSString *The user ID for which to retrieve credentials.
completionvoid (^)(NSDictionary * _Nullable, NSDictionary<NSString *, NSString *> * _Nullable, ZSMError * _Nullable)A callback function that handles the completion of the retrieval operation.

Returns
The callback function receives the following parameters:

Parameter NameData TypeDescription
dataNSDictionary *The enrollment status (attestation data) retrieved for the specified user as a dictionary.
metadataNSDictionary<NSString *, NSString *> *Additional metadata returned by the operation, if available.
errorZSMError *Error object describing any issues encountered during the retrieval process.

Enrolling (Attestation): FIDO2Client.webauthnCreate()

To initiate the creation of a new credential object, use the webauthnCreateWithOptions:completion: method. This function uses a dictionary containing the PublicKeyCredentialCreationOptions to generate the credential object, which can be stored securely for future authentication.

The response follows the PublicKeyCredential format from the WebAuthn standard.

Refer to Mozilla's online documentation on PublicKeyCredentialCreationOptions or to the W3C standard Options for Credential Creation. For response format, see the W3C standard PublicKeyCredential interface.

Usage

// Create options dictionary following FIDO2 WebAuthn standard
NSDictionary *creationOptions = @{
    @"rp": @{
        @"id": @"example.com",
        @"name": @"Example Service"
    },
    @"user": @{
        @"id": @"user-unique-id-as-base64",
        @"name": @"username",
        @"displayName": @"User's Display Name"
    },
    @"challenge": @"base64-encoded-challenge",
    @"pubKeyCredParams": @[
        @{@"type": @"public-key", @"alg": @(-7)} // ES256
    ]
    // Additional optional parameters
};

[client webauthnCreateWithOptions:creationOptions completion:^(NSDictionary * _Nullable data, NSDictionary<NSString *, NSString *> * _Nullable metadata, ZSMError * _Nullable error) {
    if (data) {
        // Handle successful creation
        NSString *rawId = data[@"rawId"];
        if (rawId) {
            // Store credential ID for future authentications
        }
    } else if (error) {
        // Handle error
    }
}];

Parameters

Parameter NameData TypeDescription
optionsNSDictionary *A dictionary representing PublicKeyCredentialCreationOptions.
completionvoid (^)(NSDictionary * _Nullable, NSDictionary<NSString *, NSString *> * _Nullable, ZSMError * _Nullable)A callback function that handles the completion of the operation.

Returns
The promise resolves with the following parameters:

Parameter NameData TypeDescription
dataNSDictionary *The attestation data generated during credential creation as a dictionary.
metadataNSDictionary<NSString *, NSString *> *Additional metadata returned by the operation, if available.
errorZSMError *Error object describing any issues encountered during the creation process.

Verifying (Assertion): FIDO2Client.webauthnGet()

To retrieve a credential object, use the webauthnGetWithOptions:completion: method. This method utilizes a dictionary containing the PublicKeyCredentialRequestOptions to authenticate the user.

The response follows the AuthenticatorAssertionResponse format from the WebAuthn standard.

Refer to Mozilla's online documentation on PublicKeyCredentialRequestOptions or to the W3C standard Options for Assertion Generation. For response format, see the W3C standard AuthenticatorAssertionResponse interface.

Usage

// Create options dictionary following FIDO2 WebAuthn standard
NSDictionary *requestOptions = @{
    @"challenge": @"base64-encoded-challenge",
    @"rpId": @"example.com",
    @"allowCredentials": @[
        @{
            @"type": @"public-key",
            @"id": @"previously-stored-credential-id"
        }
    ],
    @"timeout": @60000
};

[client webauthnGetWithOptions:requestOptions completion:^(NSDictionary * _Nullable data, NSDictionary<NSString *, NSString *> * _Nullable metadata, ZSMError * _Nullable error) {
    if (data) {
        // Handle successful assertion
        NSString *authenticatorData = data[@"authenticatorData"];
        NSString *signature = data[@"signature"];
        if (authenticatorData && signature) {
            // Verify the signature and authenticator data
        }
    } else if (error) {
        // Handle error
    }
}];

Parameters

Parameter NameData TypeDescription
optionsNSDictionary *A dictionary representing PublicKeyCredentialRequestOptions.
completionvoid (^)(NSDictionary * _Nullable, NSDictionary<NSString *, NSString *> * _Nullable, ZSMError * _Nullable)A callback function that handles the completion of the operation.

Returns
The promise resolves with the following parameters:

Parameter NameData TypeDescription
dataNSDictionary *The assertion data generated during credential verification as a dictionary.
metadataNSDictionary<NSString *, NSString *> *Additional metadata returned by the operation, if available.
errorZSMError *Error object describing any issues encountered during the assertion process.

Unbinding: FIDO2Client.unbind()

There are two versions of this method: one for removing all FIDO2 credentials for the current user, and another for removing credentials for a specific user.

For Current User

To remove all FIDO2 credentials and state for the current user from the device, use the unbindWithCompletion: method.

Usage

[clientt unbind];

Parameters
None. |

Returns
None. |

For Specific User

To remove FIDO2 credentials and state for a specific user from the device, use the unbindForUser:withCompletion: method.

Usage

NSString *userId = @"user123"; // Unique identifier for the user
[client unbindForUser:userId];

Parameters

Parameter NameData TypeDescription
userNSString *The user ID for which to remove credentials.

Returns
None.

ZSM Error Codes

NameValueExplanation
ZSMErrorCode.Error0An error occurred during the ZSM api operation.

Please check the error details for more information.
ZSMErrorCode.NetworkFailure1The co-operating server could not be reached, perhaps because the device is not connected to the internet, a port is blocked, or the server is offline.

Please retry the operation.
ZSMErrorCode.InvalidLogin2The authentication server returned an invalid login.

Please try again.
ZSMErrorCode.UnauthorizedUser3The user is not enrolled or banned and cannot complete the secure operation.

Please re-enroll or contact an administrator.
ZSMErrorCode.BadCryptograpicValue100An unsupported cryptographic parameter set was used and the secure operation was aborted.

Please retry with a valid cryptographic parameter set.
ZSMErrorCode.CryptographicFailure101The cryptographic operation failed for an undisclosed reason, such as keys out of sync, communication error, or timed out.

Please try again.
ZSMErrorCode.CryptographicKey102A message cannot be signed without generating the cryptographic key first.

Please generate the cryptographic key and then try again.
ZSMErrorCode.SecureStorageUnavailable103The secure storage for key information is currently unavailable.

Please try again later.
ZSMErrorCode.SecureStorageFailure104The secure storage operation failed due to an internal error.

Please try again.
ZSMErrorCode.SecureStorageUnauthenticated105The secure storage operation failed because the user is not authenticated.

Please authenticate the user and try again.
ZSMErrorCode.RegistrationFailure200The registration process failed due to an error.

Please try again.
ZSMErrorCode.RegistrationIncomplete201The registration process is incomplete and requires additional information.

Please provide the necessary information to complete the registration.
ZSMErrorCode.DeviceSuspended300The device is suspended and cannot perform the requested
operation.

Please contact an administrator for further assistance.
ZSMErrorCode.DeviceDeactivated301The device is deactivated and cannot perform the requested
operation.

Please contact an administrator for further assistance.
ZSMErrorCode.AccountDeactivated303The user account is deactivated and cannot perform the
requested operation.

Please contact an administrator for further assistance.
ZSMErrorCode.AuthenticationFailure400The authentication process failed due to an error.

Please try again.
ZSMErrorCode.AuthenticationIncomplete401The authentication process is incomplete and requires additional information.

Please provide the necessary information to complete the authentication.
ZSMErrorCode.DeviceNotFound500The device could not be found.

Please ensure the device is registered and try again.
ZSMErrorCode.DeviceNotLinked501The device is not linked to the user account.

Please link the device to the user account and try again.
ZSMErrorCode.DeviceAlreadyLinked502The device is already linked to another user account.

Please unlink the device and try again.
ZSMErrorCode.DeviceLinkingFailure503The device linking process failed due to an error.

Please try again.
ZSMErrorCode.DeviceUnlinkingFailure504The device unlinking process failed due to an error.

Please try again.
ZSMErrorCode.InvalidRequest600The request is invalid or malformed.

Please check the request parameters and try again.
ZSMErrorCode.InternalServerError700An internal server error occurred.

Please try again later.
ZSMErrorCode.UnknownError800An unknown error occurred.

Please contact support for assistance.

Glossary

API Consumers

API consumers are third-parties that are authorized by either a vendor or customer organization to have access to selected ZSM APIs for purposes of performing trusted third-party functions and operations. ZSM provides optional integrations for selected trusted third parties such.

Consumer

Consumers are the end-users of an application which contains the ZSM Client SDK. They are the customers of a ZSM customer organization.

CredentialID

WebAuthn identifier for a credential, synonymous with the identifier used for an enrollment. CredentialID is returned during the WebAuthn create() call and is used by the Relying Party server to store and find the Public Key needed to verify signed challenges during WebAuthn get() calls.

Customer Client Application

A customer organization’s client application (iOS, Android, or Web) that has incorporated the ZSM Cryptographic Module using the ZSM Client SDK

Customer Host Server (aka Relying Party Server)

A customer organization’s server that validates challenges signed by ZSM for consumer enrollments and verifications.

Customer Organization

ZSM customer that integrates the ZSM Client SDK into their application(s) and uses the ZSM Management APIs and Web Administration Console to manage their use of the service.

Enrollment

Enrollment is a term used to describe the unique combination of installation, consumer, application, and application environment. There is one enrollment for each unique combination of these four entities. Keysets are associated with an enrollment.

Instance ID (deprecated)

A unique identifier that identifies a specific instance of an application on a specific installation of the ZSM client on a device. This identifier is unique per application such that two applications installed on the same installation on a device have different instance identifiers. And, a specific application installed on different devices will each have their own unique instance identifiers.

Organization

Three types of organizations are defined in ZSM: API consumers, customers, and vendors.

Server Client APIs

REST APIs used to facilitate transactions between the ZSM Server and Client for consumer registration, key set generation, signing, and signature verification.

Server Management APIs

REST APIs used to manage the ZSM system, including organization management, application management, installation management, and consumer management.

User

Individual associated with a Customer who has registered an account with the ZSM service.

Vendor

This vendor organization is the organization that provides the ZSM system to customers.