2.1.0 • Published 11 months ago

@trusona/server-sdk v2.1.0

Weekly downloads
-
License
Apache-2.0
Repository
github
Last release
11 months ago

CI Maintainability Test Coverage

Trusona Server SDK

The Trusona Server SDK allows simplified interaction with the Trusona API.

Table of Contents

  1. Prerequisites
    1. Server SDK API Credentials
    2. System requirements
  2. NPM Setup
    1. Installing the Trusona Package
  3. Integrating the API into a project
    1. Creating a Trusona object
    2. Registering devices with Trusona
      1. Binding a device to a user
      2. Activating a device
    3. Creating Trusonafications
      1. Creating an Essential Trusonafication
      2. Creating an Essential Trusonafication, without user presence or a prompt
      3. Creating an Essential Trusonafication, with a TruCode
      4. Creating an Essential Trusonafication, with the user's identifier
      5. Creating an Essential Trusonafication, with the user's email
      6. Creating an Executive Trusonafication
      7. Polling for a Trusonafication Result
    4. Using TruCode for device discovery
    5. Retrieving identity documents
      1. Retrieving all identity documents for a user
      2. Retrieving a specific identity document
      3. Identity document verification statuses
      4. Identity document types
    6. Retrieving a device
    7. Deactivating a user
    8. Handling errors
    9. Using a specific Trusona region

Prerequisites

Server SDK API Credentials

The Server SDK requires API credentials that are used by the SDK to identify and authenticate requests from your application to the Trusona APIs.

The two credentials required by the SDK include a token and secret. Both are strings generated and distributed by Trusona.

NOTE: The token and secret should not be shared with anyone. They are how you authenticate to the Trusona services, and you should not check them into source control.

System requirements

The Trusona Server SDK requires Node JS 7.10.1 or above.

NPM Setup

Installing the Trusona Package

In your project, run the following command to install the latest version of the Trusona SDK.

npm i @trusona/server-sdk

Alternatively, you may also search for the NPM package in www.npmjs.com

Integrating the API into a project

Require or Import SDK

// CommonJS
const { Trusona, Trusonafication } = require("@trusona/server-sdk")
// ES Modules
import { Trusona, Trusonafication } from "@trusona/server-sdk"

Creating a Trusona object

The Trusona class is the main class you will interact with to talk to the Trusona APIs. It can be created with the token and secret provided by Trusona.

NOTE: The token and secret should not be shared with anyone. They are how you authenticate to the Trusona services, and you should not check them into source control.

const trusona = new Trusona(token, secret)

You'll also want to make sure the token and secret values aren't checked in to your project.

Registering devices with Trusona

Note: This section only applies if you are developing your own mobile app with the Trusona mobile SDK (iOS, Android). If you plan to use the Trusona app, this section can be skipped.

To get a device ready to be used with Trusona, there are three main steps:

  1. Create a device
  2. Bind the device to a user
  3. Activate the device

The first step, creating a device, will be handled by the Trusona mobile SDKs on the client. Once a device is created, the Trusona deviceIdentifier will need to be sent to your backend which can use the Trusona Server SDK to complete the next steps.

Binding a device to a user

When the backend determines which user owns the deviceIdentifier, it can bind the userIdentifier to the device in Trusona. The userIdentifier can be any String that allows you to uniquely identify the user in your system. To bind a device to a user, call the createUserDevice function.

const userDevice = await trusona.createUserDevice(yourUser.id, "deviceIdentifier")
const activationCode = userDevice.activationCode

More than one device can be bound to a user and later, when you Trusonafy them, any device bound to that user may accept the Trusonafication. Once the device is bound the user, you'll receive an activation code that can be used later to active the device.

Errors
ExceptionReason
DeviceNotFoundErrorIndicates that the request to bind the user to the device failed because the device could not be found.
DeviceAlreadyBoundErrorIndicates that the request to bind the user to the device failed because the device is already bound to a different user.
ValidationErrorIndicates that the request to bind the user to the device failed because either the deviceIdentifier or userIdentifier were blank.
TrusonaErrorIndicates that the request to bind the user to the device failed, check the message to determine the reason.

Activating a device

When the device is ready to be activated, call the activateUserDevice function with the activation code.

const result = await trusona.activateUserDevice(activationCode)

If the request is successful, the device is ready to be Trusonafied.

Exceptions
ExceptionReason
DeviceNotFoundErrorIndicates that the request to activate the device failed because the device could not be found, most likely due to an invalid activationCode.
ValidationErrorIndicates that the request to activate the device failed because the activationCode was blank.
TrusonaErrorIndicates that the request to activate the device failed, check the message to determine the reason.

Creating Trusonafications

Once a device is bound to a user, that user can be Trusonafied using the device identifier obtained from the Trusona Mobile SDK.

Creating an Essential Trusonafication

const trusona = new Trusona(token, secret)

const trusonafication = await trusona.createTrusonafication(Trusonafication.essential
  .deviceIdentifier("PBanKaajTmz_Cq1pDkrRzyeISBSBoGjExzp5r6-UjcI")
  .action("login")
  .resource("Acme Bank")
  .build())

const trusonaficationResult = await trusona.pollForTrusonaficationResult(trusonafication.id)

if (trusonaficationResult.successful) {
  // handle successful authentication
}

By default, Essential Trusonafications are built such that the user's presence is required and a prompt asking the user to "Accept" or "Reject" the Trusonafication is presented by the Trusona Mobile SDK. A user's presence is determined by their ability to interact with the device's OS Security, usually by using a biometric or entering the device passcode.

Creating an Essential Trusonafication, without user presence or a prompt

const trusona = new Trusona(token, secret)

const trusonafication = await trusona.createTrusonafication(Trusonafication.essential
  .deviceIdentifier("PBanKaajTmz_Cq1pDkrRzyeISBSBoGjExzp5r6-UjcI")
  .action("login")
  .resource("Acme Bank")
  .withoutUserPresence()
  .withoutPrompt()
  .build())

const trusonaficationResult = await trusona.pollForTrusonaficationResult(trusonafication.id)

if (trusonaficationResult.successful) {
  // handle successful authentication
}

In the above example, the addition of withoutUserPresence() and withoutPrompt() on the builder will result in a Trusonafication that can be accepted solely with possession of the device.

Creating an Essential Trusonafication, with a TruCode

const trusona = new Trusona(token, secret)

const trusonafication = await trusona.createTrusonafication(Trusonafication.essential
  .truCode("73CC202D-F866-4C72-9B43-9FCF5AF149BD")
  .action("login")
  .resource("Acme Bank")
  .build())

const trusonaficationResult = await trusona.pollForTrusonaficationResult(trusonafication.id)

if (trusonaficationResult.successful) {
  // handle successful authentication
}

In this example, instead of specifying a device identifier, you can provide an ID for a TruCode that was scanned by the Trusona Mobile SDK. This will create a Trusonafication for the device that scanned the TruCode. See Using TruCode for device discovery below for more information on using TruCodes.

Creating an Essential Trusonafication, with the user's identifier

const trusona = new Trusona(token, secret)

const trusonafication = await trusona.createTrusonafication(Trusonafication.essential
  .userIdentifier("73CC202D-F866-4C72-9B43-9FCF5AF149BD")
  .action("login")
  .resource("Acme Bank")
  .build())

const trusonaficationResult = await trusona.pollForTrusonaficationResult(trusonafication.id)

if (trusonaficationResult.successful) {
  // handle successful authentication
}

In some cases you may already know the user's identifier (i.e. in a multi-factor or step-up authentication scenario). This example shows how to issue a Trusonafication using the user's identifier.

Creating an Essential Trusonafication, with the user's email

const trusona = new Trusona(token, secret)

const trusonafication = await trusona.createTrusonafication(Trusonafication.essential
  .emailAddress("user@domain.com")
  .action("login")
  .resource("Acme Bank")
  .build())

const trusonaficationResult = await trusona.pollForTrusonaficationResult(trusonafication.id)

if (trusonaficationResult.successful) {
  // handle successful authentication
}

In some cases you may be able to send a Trusonafication to a user by specifying their email address. This is the case if one of the following is true:

  • You have verified ownership of a domain through the Trusona Developer's site
  • You have an agreement with Trusona allowing you to send Trusonafications to any email address.

Creating a Trusonafication with an email address is similar to the other use cases, except you use the emailAddress() function rather than userIdentifier() or deviceIdentifier().

Adding custom fields to a Trusonafication

If you are using the mobile SDK to build a custom app that integrates with Trusona, you have the option of including additional data on the Trusonafication which the app can use to affect its behavior. For example, you may want to include additional context on the Trusonafication prompt. You can add these custom fields by calling the customField method as shown below. The custom fields will then be available in the Trusonafication received by the mobile SDK.

Note that the custom fields are not used in the case that the Trusonafication is being handled by the Trusona app.

const trusona = new Trusona(token, secret)

const trusonafication = await trusona.createTrusonafication(Trusonafication.essential
.emailAddress("user@domain.com")
.action("login")
.resource("Acme Bank")
.customField("lastLogin", "2019-07-03T22:36:00Z")
.customField("greeting", "Good afternoon!")
.build())

const trusonaficationResult = await trusona.pollForTrusonaficationResult(trusonafication.id)

if (trusonaficationResult.successful) {
// handle successful authentication
}

Creating an Executive Trusonafication

To create an Executive Trusonafication, call the executive function initially instead of essential.

const trusona = new Trusona(token, secret)

const trusonafication = await trusona.createTrusonafication(Trusonafication.executive
  .deviceIdentifier("PBanKaajTmz_Cq1pDkrRzyeISBSBoGjExzp5r6-UjcI")
  .action("login")
  .resource("Acme Bank")
  .build())

const trusonaficationResult = await trusona.pollForTrusonaficationResult(trusonafication.id)

if (trusonaficationResult.successful) {
  // handle successful authentication
}

Executive Trusonafications require the user to scan an identity document to authenticate. An identity document needs to be registered with the user's account using the Trusona Mobile SDKs before the user can accept an Executive Trusonafication, and they must scan the same document they registered at the time of Trusonafication. Like Essential, both the prompt and user presence features can be used and are enabled by default, but they can be turned off independently by calling withoutPrompt() or withoutUserPresence(), respectively.

Polling for a Trusonafication Result

Calling pollForTrusonaficationResult() will return a Promise that does not get fulfilled until the Trusonafication is either ACCEPTED, REJECTED, or EXPIRED. You may check the status if you want to see the details of what happened, or you can just get the successful property that will only return true if it was successful.

const trusona = new Trusona(token, secret)

const trusonafication = await trusona.createTrusonafication(Trusonafication.executive
  .deviceIdentifier("PBanKaajTmz_Cq1pDkrRzyeISBSBoGjExzp5r6-UjcI")
  .action("login")
  .resource("Acme Bank")
  .build())

const trusonaficationResult = await trusona.pollForTrusonaficationResult(trusonafication.id)

if (trusonaficationResult.successful) {
  // handle successful authentication
}

Alternatively, if you already know the Trusonafication has been completed or want to implement your own polling logic, you can call getTrusonaficationResult()

Trusonafication Builder Options
NameRequiredDefaultDescription
deviceIdentifierN^1noneThe identifier as generated by the Trusona Mobile SDK.
truCodeN^1noneThe ID for a Trucode scanned by the Trusona Mobile SDK.
userIdentifierN^1noneThe identifier of the user that was registered to a device.
emailAddressN^1noneThe email address of the user that was registered to a device.
actionYnoneThe action being verified by the Trusonafication. (e.g. 'login', 'verify')
resourceYnoneThe resource being acted upon by the user. (e.g. 'website', 'account')
expiresAtNnullAn ISO-8601 UTC date that sets the expiration time of the Trusonafication.
withoutUserPresenceNfalseRemoves the requirement for the user to demonstrate presence when accepting the Trusonafication.
withoutPromptNfalseRemoves the requirement for the user to explicityly "Accept" or "Reject" the Trusonafication.
customFieldsNnullAdds custom fields to the Trusonafication, which can be inspected in the mobile SDK when receiving the Trusonafication.
callbackUrlNnullA HTTPS URL to POST to when the trusonafication has been completed (accepted, rejected, or expired). NOTE: The URL should include a randomized segment so it cannot be guessed and abused by third-parties e.g. https://your.domain.com/completed_authentications/f8abe61d-4e51-493f-97b1-464c157624f2.

^1: You must provide at least one field that would allow Trusona to determine which user to authenticate. The identifier fields are deviceIdentifier, truCode, emailAddress and userIdentifier.

Using TruCode for device discovery

In the previous section, we demonstrated how to issue a Trusonafication to a specific device using it's deviceIdentifier, but what if the user is trying to login to your website from their desktop computer and you don't know what the user's deviceIdentifier is? That's where TruCode comes in.

What is a TruCode?

A TruCode is a short-lived token that can be rendered in the form of a QR code. A Trusona enabled device can scan the QR code and send it's deviceIdentifier to Trusona. Your backend server can then fetch the deviceIdentifier from Trusona and perform a Trusonafication on the device.

Rendering a TruCode

To render a TruCode, you can use the Trusona Web SDK. Because TruCodes are short-lived, they need to be refreshed periodically. The Trusona Web SDK will handle the fetching of TruCodes, polling the status to see if they've been paired, refreshing them before they expire, and, when finally paired, return the truCodeId that the backend can use to look up the device identifier.

First get the Web SDK Config for your system from the Server SDK. The Web SDK will need this configuration later when rendering TruCode.

const trusona = new Trusona(token, secret)

const webSdkConfig = trusona.getWebSdkConfig() // {"truCodeUrl": "https://example.net", "relyingPartyId": "C97A800D-75E8-43B5-87A5-3282B0DD8576" }

Include the trucode.js script tag before the </body> of your document

  <!-- existing content -->
  <script type="text/javascript" src="https://static.trusona.net/web-sdk/js/trucode-0.6.13.js"></script>
  </body>
</html>

Add an element to your page where you want the TruCode rendered in.

<div id="tru-code"></div>

Call the renderTruCode function in the Web SDK using the Web SDK Config from the Server SDK.

<script>
  var truCodeConfig = #{webSdkConfig} // example: {"truCodeUrl": "https://example.net", "relyingPartyId": "C97A800D-75E8-43B5-87A5-3282B0DD8576" }

  Trusona.renderTruCode({
    truCodeConfig: truCodeConfig,
    truCodeElement: document.getElementById('tru-code'),
    onPaired: function(truCodeId) {
      // send the truCodeId to your backend service
    },
    onError: function() {
      // handle if there were errors fetching truCodes
    }
   })
</script>

When the TruCode has been scanned by a Trusona enabled device, the truCodeId will be passed into the onPaired callback where you can relay it to your backend to get the deviceIdentifier.

Retrieving identity documents

Identity documents can be registered using the Trusona Mobile SDK and are required for being able to accept Executive Trusonafications. Depending on your agreement with Trusona, the identity documents may also be verified using a third-party verification system. The Server SDK allows you to get all the identity documents that were registered by a user or to get a specific identity document by ID. This can be useful to see if a user is capable of accepting Executive Trusonafications or to check the result of a third-party verification.

Retrieving all identity documents for a user

const trusona = new Trusona(token, secret)

const documents = await trusona.findIdentityDocuments(userIdentifier)

if (documents.length === 0) {
  // Not capable of accepting Executive Trusonafications
} else {
  // Is capable of accepting Executive Trusonafications
}

This example shows how to determine if a user is capable of accepting Executive Trusonaficaitons. The call to the findIdentityDocuments function with the userIdentifier that was registered with Trusona will return a list of IdentityDocuments. If the list is empty, then no identity documents have been registered and the user will not be able to scan their document to accept the Trusonafication.

NOTE: The verificationStatus of an identity document is not considered during the acceptance of a Trusonafication. If you only want to allow users with VERIFIED documents you'll have to check the status prior to issuing the Trusonafication.

Retrieving a specific identity document

const trusona = new Trusona(token, secret)

const document = await trusona.getIdentityDocument(document.id)

document.verificationStatus // UNVERIFIED, UNVERIFIABLE, VERIFIED, or FAILED

Here we are getting a specific identity document by ID. Since the ID is generated at the time the document is registered (on the mobile device), you'll have to send the ID to your backend server and then call the getIdentityDocument function in order to check the status. See all verification statuses.

Identity document verification statuses

StatusDescription
UNVERIFIEDVerification of the identity document has not been attempted.
UNVERIFIABLEVerification of the identity document was attempted, but no verification determination has been made (i.e. the third-party verification was not available in that region).
VERIFIEDThe document was sucessfully verified.
FAILEDThe document failed verification.

Identity document properties

NameTypeDescription
idStringThe ID of the document that was generated when it was registered.
hashStringThe hash of the raw data of the document that was scanned. Trusona does not store any of the raw information from the original document
verificationStatusStringThe status of the third-party verification that was performed, if any. See all verification statuses.
verifiedAtDateThe date when the verification status was determined.
typeStringThe type of the identity document. See all identity document types.

Identity document verification statuses

StatusDescription
UNVERIFIEDVerification of the identity document has not been attempted.
UNVERIFIABLEVerification of the identity document was attempted, but no verification determination has been made (i.e. the third-party verification was not available in that region).
VERIFIEDThe document was sucessfully verified.
FAILEDThe document failed verification.

Identity document types

TypeDescription
AAMVA_DRIVERS_LICENSEA U.S. or Canada issued driver's license.

Retrieving a device

If you want to check whether or not a device has been activated, or when it was activated, you can look it up in Trusona using the device's identifier.

const trusona = new Trusona(token, secret)

const device = await trusona.getDevice("r1ByVyVKJ7TRgU0RPX0-THMTD_CO3VrCSNqLpJFmhms")

if (device.active) {
  // Device has been activated and can receive/respond to Trusonafications
}

Deactivating a user

You may wish to disable a user from having the ability to authenticate from any of the devices they have registered with. To deactivate a user:

const trusona = new Trusona(token, secret)

const device = await trusona.deactivateUser("73CC202D-F866-4C72-9B43-9FCF5AF149BD")

if (!device.active) {
  // Device has been deactivated
}

The deactivated user can be reactivated at a later date by binding them to a new device in Trusona.

Handling errors

Failed requests get thrown as a TrusonaError, which TrusonaError a message about what went wrong and what you should do to fix the problem. Some calls may also throw subclasses of TrusonaError for scenarios where it might be possible to correct the issue programmatically. It's up to you if you want to handle those specific scenarios or just catch all TrusonaErrors. If a request fails validation and has error messages for specific fields, a ValidationError will get thrown and you can call fieldErrors to inspect the error messages associated with each field that failed.

Using a specific Trusona region

All users are provisioned in the default region. Unless otherwise noted, you will not need to configure Trusona to use a specific region. If you have been provisioned in a specific region, you will need to point the SDK to use that region. This can be done by passing the appropriate region endpoint to the constructor. For example:

const trusona = new Trusona(token, secret, Trusona.EU_PRODUCTION)

Need additional help?

Contact us at engineering@trusona.com