Skip to content
This repository has been archived by the owner on Jan 11, 2024. It is now read-only.

Latest commit

 

History

History
343 lines (277 loc) · 14.4 KB

File metadata and controls

343 lines (277 loc) · 14.4 KB

BlackBerry Spark Communications Services

Quick Start for JavaScript

The Quick Start example application demonstrates how you can get started with the BlackBerry Spark Communications Services.


Features

The Quick Start example application demonstrates the following functionality:

  • Ensure that the JavaScript environment can run the SDK
  • Authenticate a user and get an access token
  • Instantiate the SDK.
  • Setup the SDK instance.

Getting Started

This example requires the Spark Communications SDK, which you can find along with related resources at the locations below.

YouTube Getting Started Video

Getting started video

This example application works in a sandbox domain with user authentication disabled and the BlackBerry Key Management Service enabled. See the Download & Configure section of the Developer Guide to get started configuring a domain in the sandbox.

When you have a domain in the sandbox, edit Quick Starts's config_mock.js file to configure the example with your domain ID and a key passcode.

Set the SDK_CONFIG.domain parameter to your sandbox domain ID.

const SDK_CONFIG = {
  domain: 'your_domain_id'
};

Set the USER_ID parameter to the user ID that will be associated with the SDK instance being set up in this example.

const USER_ID = 'user1';

Set the KEY_PASSCODE parameter to the string used to protect the configured user's keys stored in the BlackBerry Key Management Service. Real applications should not use the same passcode for all users. However, it allows this example application to be smaller and focus on demonstrating its call functionality instead of passcode management.

const KEY_PASSCODE = 'passcode';

Walkthrough

Follow this guide for a walkthrough showing how to authenticate with the SDK using Google Sign-in for Web.

Authentication and access tokens

The AuthenticationManager in this example is the MockAuthManager from the support library. The MockAuthManager does not interact with a real identity provider, and so, has a function that can be overridden to provide the user's ID.

When AuthManager.authenticate() is called, asynchronous interaction with the identity provider is started. When control is returned to the example application, the authorized user's identity will be known.

Asynchronous errors can be thrown during authentication, so they must be handled accordingly. This example displays the error and emits it to the console.

Please refer to the Developer Guide for more information on Identity Providers.

The support library also provides the GoogleAuthManager and the AzureAuthManager classes that interact with real identity providers.

  try {
    // Setup the authentication manager for the application.
    const authManager = new AuthenticationManager(AUTH_CONFIGURATION);
    if (AuthenticationManager.name === 'MockAuthManager') {
      // We are using the MockAuthmanager, so we need to override how it
      // acquires the local user's user ID.
      authManager.getUserId = () => (
        USER_ID
        ? Promise.resolve(USER_ID)
        : Promise.reject(new Error('USER_ID is not defined'))
      );
    }

    // Authenticate the user.  Configurations that use a real identity
    // provider (IDP) will redirect the browser to the IDPs authentication
    // page.
    const authUserInfo = await authManager.authenticate();
    if (!authUserInfo) {
      console.warn('Redirecting for authentication.');
      return;
    }
  }
  catch(error) {
    // Display any error that was encountered.
    $('#error').text(error);
    console.error(`QuickStart encountered an error; error=${error}`);
  }

The authentication manager provides a getBbmSdkToken() API that will perform the necessary interaction with the identity provider to get an access token suitable for use with the SDK.

Instantiate the SDK

To create an instance of the SparkCommunications object, you must call its constructor and specify the configuration to be used.

The domain and environment properties are taken directly from the example's configuration file.

The userId property is taken from the user information object that was created during authentication. This is the ID assigned by the identity provider for the logged in user.

The getToken property provides the SDK with a way to get a current access token associated with the logged-in user. This token will be verified by the BlackBerry Infrastructure.

The description property describes the type of client that is using the SDK.

The kmsArgonWasmUrl property is only required if the argon2.wasm module is not in the same directory as your application. If you followed the Exploring the Examples section of the Developer Guide, then the default value set by the example will already be set correctly.

  // Instantiate the SDK.
  //
  // We use the SDK_CONFIG imported from the example's configuration
  // file to override some of the options used to configure the SDK.
  //
  // This example might not work if your SDK_CONFIG specifies any of the
  // parameters assigned below.
  const sdk = new SparkCommunications(Object.assign(
    {
      // You must specify your domain in the SDK_CONFIG.

      // This example requires user authentication to be disabled, which is
      // not supported in production.
      sandbox: true,

      // The user ID to use when connecting to the BlackBerry
      // Infrastructure.  We use the value returned by our identity
      // provider.
      userId: authUserInfo.userId,

      // The access token to use when connecting to the BlackBerry
      // Infrastructure.  We use the value returned by our identity
      // provider.
      getToken: () => authManager.getBbmSdkToken(),

      // We just use the browser's userAgent string to describe this
      // endpoint.
      description: navigator.userAgent,

      // Set the Argon2 WASM file location if it has not already been set.  If
      // you have put the argon2.wasm file in a custom location, you can
      // override this option in the imported SDK_CONFIG.
      kmsArgonWasmUrl: SDK_CONFIG.kmsArgonWasmUrl || '../../sdk/argon2.wasm'
    },
    SDK_CONFIG
  ));

Monitor the setup state

When setup is started, the SDK will emit the setupState event when ever the SparkCommunications.setupState property changes. Use this event to track the SDK's progress through setup.

When using the the BlackBerry Key Management Service, the setupState will transition to SyncRequired when the SDK is ready to sync the user's keys. These keys are protected, and the SDK requires a passcode so that it can protect newly generated keys or unprotect existing keys.

You can tell if the user needs to generate new keys or if they have existing keys by looking at the SparkCommunications.syncPasscodeState while the setupState is SyncRequired.

Once in the SyncRequired setup state, you must tell the SDK how to proceed by calling SparkCommunications.syncStart(). When syncStart() is called, the setupState will advance to to SyncStarted. The followign table describes the behavior of syncStart() based on the different possible combinations of SyncPasscodeState and SyncStartAction.

SyncPasscodeState SyncStartAction Behavior
New New New keys will be generated and the passcode will be used to protect the keys before exporting them to the BlackBerry Key Management Service.
New Existing Error. This is not a valid combination.
Existing New The existing keys will be ignored. New keys will be generated and the passcode will be used to protect the keys before exporting them to the BlackBerry Key Management Service.
Existing Existing The passcode will be used to unprotect the keys being imported from the BlackBerry Key Management Service. If the passcode fails to unprotect the keys, the setupState will regress to SyncRequired so that you can try again with a new passcode or generate new keys.

The SDK setup will be complete when the setupState transitions to Success. After this has occurred, you can begin using the SDK's messaging and media APIs.

When setup has completed, the SDK will remain setup until SparkCommunications.shutdown() is called or a fatal error occurs. When the SDK is shutdown or encounters a fatal error, the setupState will regress to NotInitiated. You can monitor for setupState events after setup has completed to learn when the SDK is no longer set up.

  // Handle changes to the SDK's setup state.
  let isSyncStarted = false;
  sdk.on('setupState', async state => {
    // As setup progresses, update the display with the current setup
    // state.
    $('#setupState').text(state.value);
    console.log(`QuickStart: Endpoint setup state: ${state.value}`);

    switch (state.value) {
      case SparkCommunications.SetupState.Success: {
        // Setup was successful.
        resolve();
        break;
      }
      case SparkCommunications.SetupState.SyncRequired: {
        if (isSyncStarted) {
          // We have already tried to sync the user's keys using the
          // given passcode.  For simplicity in this example, we don't
          // try to recover when the configured passcode cannot be
          // used.
          reject(new Error(
            'Failed to get user keys using provided KEY_PASSCODE.'));
          return;
        }

        // We need to provide the SDK with the user's key passcode.
        sdk.syncStart(
          // For simplicity in this example, we always use the
          // configured passcode.
          KEY_PASSCODE,

          // Does the user have existing keys?
          sdk.syncPasscodeState === SparkCommunications.SyncPasscodeState.New
          // No, we must create new keys.  The key passcode will be
          // used to protect the new keys.
          ? SparkCommunications.SyncStartAction.New
          // Yes, we have existing keys.  The key passcode will be
          // used to unprotect the keys.
          : SparkCommunications.SyncStartAction.Existing
        );
        break;
      }
      case SparkCommunications.SetupState.SyncStarted: {
        // Syncing of the user's keys has started.  We remember this so
        // that we can tell if the setup state regresses.
        isSyncStarted = true;
        break;
      }
    }
  });

Monitor for setup errors

When an error occurs that will cause the SDK setup to fail, a setupError event will be emitted.

When setup has completed, the SDK may still emit a setupError event if a fatal error occurs. You can monitor for setupError events after setup has completed to know when a fatal error occurs.

When a setup error occurs, whether before or after setup completes, the setupState will regress to NotInitiated.

  // Any setup error received will fail the SDK setup promise.
  sdk.on('setupError', error => {
   reject(new Error(`Endpoint setup failed: ${error.value}`));
  });

Start setup

Call SparkCommunications.setupStart() to begin setting up the SDK.

  // Start the SDK setup.
  sdk.setupStart();

License

These examples are released as Open Source and licensed under the Apache 2.0 License.

Reporting Issues and Feature Requests

If you find a issue in one of the Samples or have a Feature Request, simply file an issue.