Installation and usage

The Tanker Client SDK is distributed as the following npm packages:

  • @tanker/client-browser for Web applications
  • @tanker/client-node for Node.js client applications

Other packages are available and are documented in the VerificationUI and FakeAuth sections. They can be installed and used the same way as the @tanker/client-* packages.

npm install @tanker/client-browser

To use Tanker in your web application:

import { Tanker } from '@tanker/client-browser';
// or...
const { Tanker } = require('@tanker/client-browser');

const config = { appId: 'your-app-id' };
const tanker = new Tanker(config);

If needed, you can alternatively use the self-contained UMD file from the @tanker/client-browser npm package (./umd/tanker-client-browser.min.js), or from unpkg.com, with the following syntax:

<script src=".../path/to/umd/tanker-client-browser.min.js"></script>
<script>
  const { Tanker } = window.Tanker;

  const config = { appId: 'your-app-id' };
  const tanker = new Tanker(config);
</script>

To use Tanker in your node application:

import { Tanker } from '@tanker/client-node';
// or...
const { Tanker } = require('@tanker/client-node');

const path = // A path where your application can store persistent data
const config = { appId: 'your-app-id', dataStore: { dbPath: path } };
const tanker = new Tanker(config);

Note

This documentation uses flow type annotations.
The custom b64string type represents binary data encoded in a base 64 string.

Known issue

We use a version of libsodium that has a bug when used with webpack, to keep compatibility with Internet Explorer. The encountered error is:

Module not found: Error: Can't resolve 'fs'

As a workaround, you can add the following to your webpack configuration:

webpackConfig.node = {
  fs: 'empty',
  crypto: 'empty',
}

Supported platforms

The SDK is continuously tested with several versions of Firefox, Chrome, Edge, Internet Explorer, and Safari. We use browser stack in addition to our own CI system.

Note that although all examples are written using latest ECMAScript standard, you can still use the Tanker SDK in ECMAScript 5 compatible code.

Asynchronous

The Tanker API is asynchronous, meaning that all methods of the Tanker object return JavaScript promises. For any method() returning a result asynchronously, you can either await the call:

const result = await tanker.method(/*...*/);

Or chain it with then if you need to be compatible with ECMAScript 5:

tanker.method(/*...*/).then(function (result) {
  // continue work here
});

Error handling

import { errors } from '@tanker/client-browser';

try {
  await tanker.start(...);
} catch(e) {
  if (e instanceof errors.InvalidArgument) {
    /* specific Tanker error handling */
  } else if (e instanceof errors.TankerError) {
    /* generic Tanker error handling */
  } else {
    /* generic non-Tanker error handling */
  }
}

All errors thrown by Tanker extend the same TankerError base class and have the following fields:

Field Description
name the name of the (sub)class as a string
message additional details about the error

Here is the list of possible errors:

Error Description
DecryptionFailed A decryption operation failed
ExpiredVerification The identity verification is expired
GroupTooBig The group would exceed the maximum member limit (1000)
InternalError Tanker internal error, thrown as a last resort
InvalidArgument Developer error, one of the function's argument is invalid
InvalidVerification An invalid identity verification was provided
NetworkError Network error, e.g. connection lost or the Tanker server is not reachable
OperationCanceled An asynchronous operation was canceled when Tanker stopped
PreconditionFailed Developer error, a function's precondition was violated
TooManyAttempts An operation was attempted too many times, please try again later
DeviceRevoked The current device is already revoked and cannot be used anymore
Conflict There was a conflict with a concurrent operation from another device/user, try again

Version

This is a static variable containing the SDK version as a string.

const version = Tanker.version;

Constructor

const config = { appId: 'your-app-id' };
const tanker = new Tanker(config);
Parameters Description
config: Object The configuration of this Tanker instance, containing:
config.appId: b64string The app ID

Session management

start

Starts a Tanker session and returns a status.

The Tanker status must be STOPPED.

function start(identity: b64string): Promise<number>

The returned promise resolves in a value in Tanker.statuses.

Parameters
identity: string A Tanker identity
Returns
Promise<READY> The session is ready and fully operational
Promise<IDENTITY_REGISTRATION_NEEDED> First use of the identity. registerIdentity() must be called.
Promise<IDENTITY_VERIFICATION_NEEDED> New device for this identity. verifyIdentity() must be called.
Throws Description
InvalidArgument The provided identity is invalid
PreconditionFailed The status is not STOPPED
NetworkError Network error, e.g. connection lost or the Tanker server is not reachable
DeviceRevoked The current device is already revoked and cannot be used anymore

stop

Stops the current Tanker session.

function stop(): Promise<void>
Returns
Promise The promise is fulfilled once the stop operation is done

status

The status of a Tanker session is available as the status property:

const status = tanker.status;

Possible status values are defined in Tanker.statuses:

Status Description
Tanker.statuses.STOPPED The session is stopped. start() can be called on it.
Tanker.statuses.READY The session is ready and fully operational
Tanker.statuses.IDENTITY_VERIFICATION_NEEDED The session needs the identity to be verified to become READY
Tanker.statuses.IDENTITY_REGISTRATION_NEEDED This identity is not associated with any verification method. One must be registered.

To monitor status changes in your application, listen to the statusChange event.

Identity verification

Verification

The Verification object is a plain-data object that must match one of the following formats:

{ email: string, verificationCode: string }
{ oidcIdToken: string }
{ passphrase: string }
{ verificationKey: string }

A Verification object is typically used to perform an identity verification, or to register a new identity verification method.

Verification Method

The VerificationMethod object is a plain-data object that must match one of the following formats:

{ type: 'email', email: string }
{ type: 'oidcIdToken' }
{ type: 'passphrase' }
{ type: 'verificationKey' }

VerificationMethod objects are returned by functions that list verification methods available for an upcoming identity verification, e.g. getVerificationMethods() and attachProvisionalIdentity().

registerIdentity

Registers the user's identity with which start() has been called, and starts the session.

The Tanker status must be IDENTITY_REGISTRATION_NEEDED.

function registerIdentity(verification: Verification): Promise<void>
Parameters
verification: Verification The verification to use for identity registration
Returns
Promise The promise is fulfilled once the registration is done
Throws Description
InvalidArgument The verification is ill-formed or incomplete
PreconditionFailed The status is not IDENTITY_REGISTRATION_NEEDED
ExpiredVerification The verification expired
InvalidVerification The verification is invalid
TooManyAttempts Too many verification attempts occurred. Please retry later.
NetworkError Network error, e.g. connection lost or the Tanker server is not reachable
DeviceRevoked The current device is already revoked and cannot be used anymore

verifyIdentity

Verifies the user's identity with which start has been called, and starts the session.

The Tanker status must be IDENTITY_VERIFICATION_NEEDED.

function verifyIdentity(verification: Verification): Promise<void>
Parameters
verification: Verification The verification to use
Returns
Promise The promise is fulfilled once the verification is complete
Throws Description
InvalidArgument The verification is ill-formed or incomplete
PreconditionFailed The status is not IDENTITY_VERIFICATION_NEEDED
ExpiredVerification The verification expired
InvalidVerification The verification is invalid
TooManyAttempts Too many verification attempts occurred. Please retry later.
NetworkError Network error, e.g. connection lost or the Tanker server is not reachable
DeviceRevoked The current device is already revoked and cannot be used anymore
Conflict There was a conflict with a concurrent operation from another device/user, try again

setVerificationMethod

Adds or overrides a verification method.

The Tanker status must be READY.

function setVerificationMethod(verification: Verification): Promise<void>
Parameters Description
verification: Verification The verification to use
Returns
Promise The promise is fulfilled when the verification method has been set or updated
Throws Description
InvalidArgument The verification is ill-formed or incomplete
ExpiredVerification The verification expired
InvalidVerification The verification is invalid
PreconditionFailed The status is not READY
TooManyAttempts Too many verification attempts occurred. Please retry later.
NetworkError Network error, e.g. connection lost or the Tanker server is not reachable
DeviceRevoked The current device is already revoked and cannot be used anymore

getVerificationMethods

Returns the list of registered verification methods.

The Tanker status must be either IDENTITY_VERIFICATION_NEEDED or READY.

function getVerificationMethods(): Promise<Array<VerificationMethod>>
Returns
Promise<Array<VerificationMethod>> The list of VerificationMethods already set
Throws Description
PreconditionFailed The status is neither IDENTITY_VERIFICATION_NEEDED nor READY
NetworkError Network error, e.g. connection lost or the Tanker server is not reachable
DeviceRevoked The current device is already revoked and cannot be used anymore

generateVerificationKey

Generates a verification key, registers its public part on Tanker's servers, and returns its private part, which is required to verify the user's identity.

The Tanker status must be IDENTITY_REGISTRATION_NEEDED.

function generateVerificationKey(): Promise<string>

Once the verification key has been generated, it is not possible to set up high-level verification methods (e.g. email/passphrase).

The opposite is also true: no high-level verification method must have been set up before calling this function.

It is NOT possible to generate several verification keys.

Warning

This is a low level function for specific use-cases only, as it can have severe security implications. Use it only if high-level identity verification doesn't fit your needs, and you fully understand how it works. Don't hesitate to contact us for help.

Returns
Promise<string> The generated verification key
Throws Description
PreconditionFailed The status is not IDENTITY_REGISTRATION_NEEDED
NetworkError Network error, e.g. connection lost or the Tanker server is not reachable
DeviceRevoked The current device is already revoked and cannot be used anymore

Device management

deviceId

A property containing the current device's ID.

The Tanker status must be READY.

get deviceId(): b64string;
Contains
b64string The current device's ID
Throws Description
PreconditionFailed The status is not READY

getDeviceList

Retrieves the user's devices list.

The Tanker status must be READY.

function getDeviceList(): Promise<Array<Device>>
Returns
Promise<Array<Device>> An array of devices

Each Device is an object describing a device, with the following properties:

Fields Description
id: b64string The device ID of the device
isRevoked: boolean true if the device is already revoked and cannot be used anymore
Throws Description
PreconditionFailed The status is not READY
NetworkError Network error, e.g. connection lost or the Tanker server is not reachable
DeviceRevoked The current device is already revoked and cannot be used anymore

revokeDevice

Revokes one of the user's devices.

The Tanker status must be READY.

function revokeDevice(deviceId: b64string): Promise<void>
Parameters
deviceId: b64string The device ID of the device to be revoked
Throws Description
InvalidArgument The device ID is not one of the users'
PreconditionFailed The status is not READY
NetworkError Network error, e.g. connection lost or the Tanker server is not reachable
DeviceRevoked The current device is already revoked and cannot be used anymore
Conflict There was a conflict with a concurrent operation from another device/user, try again

Encryption

Binary data handling

Encrypting binary data

Just like you can used encrypt() to encrypt strings, you need to call encryptData() to encrypt binary resources:

const clearFile = new File(/*...*/);
const encryptedFile = await tanker.encryptData(clearFile);

encryptedFile instanceof File; // true;

The encryptData() method accepts ArrayBuffer, Buffer, Blob, File and Uint8Array instances as input, and will return an encrypted resource in the same format by default.

You can also explicitly set the type option to ArrayBuffer, Buffer, Blob, File or Uint8Array to request a different output type:

const clearData = new Uint8Array(32);
const encryptedBlob = await tanker.encryptData(clearData, { type: Blob });

encryptedBlob instanceof Blob; // true; (instead of Uint8Array by default)

For File and Blob outputs, you can specify a mime option to set the MIME type on the output. By default, the MIME type of the input will be set to the output.

For File outputs, you can specify a name option to set on the output. By default, the name of a File input will be set to the output.

const encryptedFile = await tanker.encryptData(clearFile, {
    type: File,
    mime: 'application/octet-stream', // default: clearFile.mime
    name: `${clearFile.name}.enc`     // default: clearFile.name
}):

Sharing binary data

Regarding sharing, encryptData() behaves exactly like encrypt():

  • by default, a user's encrypted data can only be decrypted on the devices of this user
  • you can specify additional recipients by passing EncryptionOptions, so that they can decryptData() those data.

Decrypting binary data

To decrypt some data encrypted with encryptData(), simply give it to decryptData(). It will work the same whether the content was encrypted by the current user, or shared with them.

const clearFile = await tanker.decryptData(encryptedFile);

decryptData() will throw an error if the user does not have access to this data (i.e. if the data was not shared with them).

Similarly to encryptData(), decryptData() accepts ArrayBuffer, Blob, File and Uint8Array instances as input, and returns a decrypted resource in the same format by default.

Most options available on encryptData() are available on decryptData() too: type, mime and name.

encrypt

Encrypts a string and returns the result as an ArrayBuffer, Buffer, Blob, File or Uint8Array (default). The resulting encrypted resource will be shared with either or both individual users and groups specified in the EncryptionOptions.

The Tanker status must be READY.

type Data = ArrayBuffer | Buffer | Blob | File | Uint8Array;

function encrypt(clearText: string, options?: EncryptionOptions): Promise<Data>

Note

The clearText string is UTF-8 encoded prior to encryption.

Parameters
clearText: string The clear text to be encrypted
options?: EncryptionOptions Encryption and sharing options (optional)
Returns
Promise<Uint8Array> The encrypted data
Throws Description
InvalidArgument Some recipients (groups or users) have not been found
PreconditionFailed The status is not READY
NetworkError Network error, e.g. connection lost or the Tanker server is not reachable
DeviceRevoked The current device is already revoked and cannot be used anymore

encryptData

Encrypts raw bytes passed as an ArrayBuffer, Buffer, Blob, File or Uint8Array and returns the resulting encrypted resource in the same format as the input by default. Additional output options are available in EncryptionOptions.

The Tanker status must be READY.

type Data = ArrayBuffer | Buffer | Blob | File | Uint8Array;

function encryptData(clearData: Data, options?: EncryptionOptions): Promise<Data>

The resource will be shared with either or both individual users and groups specified in the EncryptionOptions.

Parameters
(Browsers) clearData: Data The clear data to encrypt as an ArrayBuffer, Blob, File or Uint8Array
(Node.js) clearData: Data The clear data to encrypt as an ArrayBuffer, Buffer or Uint8Array
options?: EncryptionOptions Encryption and sharing options (optional)
Returns
Promise<Data> The encrypted data in the specified type format, or in the same format as the input otherwise
Throws Description
InvalidArgument Some recipients (groups or users) have not been found
PreconditionFailed The status is not READY
NetworkError Network error, e.g. connection lost or the Tanker server is not reachable
DeviceRevoked The current device is already revoked and cannot be used anymore

EncryptionOptions

The shareWithUsers and shareWithGroups options allow you to specify who will be able to decrypt the resource. If none is provided, only the resource creator will be able to decrypt it.

In general, if you need to share a resource with multiple users, it is advised to create groups and use shareWithGroups.

Fields Default Description
shareWithUsers: Array<string> [] User PublicTankerIdentities to share with (the current user's identity will be automatically appended)
shareWithGroups: Array<string> [] Group IDs to share with

Additional options are available to define the output of encryption methods:

Fields Default Description
(Browsers) type: Class (same class as input) Output format among ArrayBuffer, Blob, File and Uint8Array
(Node.js) type: Class (same class as input) Output format among ArrayBuffer, Buffer and Uint8Array
mime: string application/octet-stream Output MIME type (Blob & File types only)
name: string '' Output file name (File type only)
onProgress: Function (none) A handler function to track progress. It will be called several times with a single argument in the following format: { currentBytes: number, totalBytes: number }

decrypt

Decrypts a resource passed as an ArrayBuffer, Buffer, Blob, File or Uint8Array, decodes it from UTF-8 to a DOM string, and returns it.

type Data = ArrayBuffer | Buffer | Blob | File | Uint8Array;

function decrypt(encryptedData: Data, options?: DecryptionOptions): Promise<string>
Parameters
encryptedData: Uint8Array The encrypted data to be decrypted
options?: DecryptionOptions Decryption options: only onProgress is available (optional)
Returns
Promise<string> The decrypted string
Throws Description
DecryptionFailed The encrypted data is either corrupted or the current user has no right to decrypt it
PreconditionFailed The status is not READY
NetworkError Network error, e.g. connection lost or the Tanker server is not reachable, and the key is not locally available
DeviceRevoked The current device is already revoked and cannot be used anymore

decryptData

Decrypts a resource passed as an ArrayBuffer, Buffer, Blob, File or Uint8Array and returns the original raw bytes resource in the same format as the input by default. Additional output options are available in DecryptionOptions.

type Data = Uint8Array | ArrayBuffer | Buffer | Blob | File;

function decryptData(encryptedData: Data, options?: DecryptionOptions): Promise<Data>
Parameters
(Browsers) encryptedData: Data The encrypted data to decrypt as an ArrayBuffer, Blob, File or Uint8Array
(Node.js) encryptedData: Data The encrypted data to decrypt as an ArrayBuffer, Buffer or Uint8Array
options?: DecryptionOptions Decryption options (optional)
Returns
Promise<Data> The decrypted data in the specified type format, or in the same format as the input otherwise
Throws Description
DecryptionFailed The encrypted data is either corrupted or the current user has no right to decrypt it
PreconditionFailed The status is not READY
NetworkError Network error, e.g. connection lost or the Tanker server is not reachable, and the key is not locally available
DeviceRevoked The current device is already revoked and cannot be used anymore

DecryptionOptions

In the context of a decryptData() call only, the following options are available:

Fields Default Description
(Browsers) type: Class (same class as input) Output format among ArrayBuffer, Blob and File
(Node.js) type: Class (same class as input) Output format among ArrayBuffer, Buffer and Uint8Array
mime: string application/octet-stream Output MIME type (Blob & File types only)
name: string '' Output file name (File type only)
onProgress: Function (none) A handler function to track progress. It will be called several times with a single argument in the following format: { currentBytes: number, totalBytes: number }

Groups management

createGroup

Creates a group with users' public identities, and returns its ID.

The Tanker status must be READY.

function createGroup(publicIdentities: Array<string>): Promise<b64string>

Note

The maximum number of users per group is 1000.

Parameters
publicIdentities: Array<string> Group members' public identities
Returns
Promise<b64string> The newly created group's ID
Throws Description
InvalidArgument Some recipients (groups or users) have not been found. The whole operation is canceled.
PreconditionFailed The status is not READY
NetworkError Network error, e.g. connection lost or the Tanker server is not reachable
DeviceRevoked The current device is already revoked and cannot be used anymore

updateGroupMembers

Add members to an existing group.

The Tanker status must be READY.

function updateGroupMembers(groupId: string, { usersToAdd: Array<string> }): Promise<void>;

The new group members will automatically get access to all resources previously shared with the group.

Parameters
groupId: string Group ID to modify
usersToAdd: Array<string> Public identities of users to add to the group
Returns
Promise The promise is fulfilled once the operation is done
Throws Description
InvalidArgument Some recipients (groups or users) have not been found. The whole operation is canceled.
PreconditionFailed The status is not READY
NetworkError Network error, e.g. connection lost or the Tanker server is not reachable
DeviceRevoked The current device is already revoked and cannot be used anymore
Conflict There was a conflict with a concurrent operation from another device/user, try again

Sharing

Sharing a resource can be done during encryption, using the encryption options.

getResourceId

Retrieves an encrypted resource's ID.

type Data = Uint8Array | ArrayBuffer | Buffer | Blob | File;

function getResourceId(encryptedData: Data): Promise<b64string>

The resource ID can then be used to call share.

Note

This function does not have any requirement on Tanker's status.

Parameters
(Browsers) encryptedData: Data The encrypted resource of which you want the ID as an ArrayBuffer, Blob, File or Uint8Array
(Node.js) encryptedData: Data The encrypted resource of which you want the ID as an ArrayBuffer, Buffer or Uint8Array
Returns
Promise<b64string> The ID of the given encrypted resource
Throws Description
InvalidArgument The argument is an invalid resource
PreconditionFailed The status is not READY

share

Shares resources with users and groups.

The Tanker status must be READY.

type SharingOptions = { shareWithUsers?: Array<string>, shareWithGroups?: Array<string> };

function share(resourceIds: Array<b64string>, options: SharingOptions): Promise<void>

This function either fully succeeds or fails. In this case, it does not share with any recipient.

Parameters
resourceIds: Array<b64string> Resource IDs to share
options: SharingOptions Object defining the recipients of the sharing operation
Returns
Promise The promise is fulfilled once the operation is done
Throws Description
PreconditionFailed The status is not READY
InvalidArgument Some recipients (groups or users) have not been found
InvalidArgument Some resource IDs have not been found
NetworkError Network error, e.g. connection lost or the Tanker server is not reachable
DeviceRevoked The current device is already revoked and cannot be used anymore

SharingOptions

The shareWithUsers and shareWithGroups options allow you to specify who will be able to decrypt the resource.

In general, if you need to share a resource with multiple users, it is advised to create groups and use shareWithGroups.

Fields Default Description
shareWithUsers: Array<string> [] Public tanker identities of users to share with (the current user's identity will be automatically appended)
shareWithGroups: Array<string> [] Group IDs to share with

Pre-registration sharing

attachProvisionalIdentity

Attaches a provisional identity to the user.

The Tanker status must be READY.

function attachProvisionalIdentity(provisionalIdentity: string): Promise<AttachResult>

Depending on the result, verifying the provisional identity with verifyProvisionalIdentity might be necessary.

Parameters
provisionalIdentity: string A provisional identity
Returns
Promise<AttachResult> An AttachResult
Throws Description
InvalidArgument The provided provisional identity is invalid
PreconditionFailed The status is not READY
NetworkError Network error, e.g. connection lost or the Tanker server is not reachable
DeviceRevoked The current device is already revoked and cannot be used anymore

AttachResult

The attachProvisionalIdentity function returns a type with the following properties:

Field Description
status: Status The provisional identity's status. Either READY or IDENTITY_VERIFICATION_NEEDED
verificationMethod: VerificationMethod A verification method containing the email matching the created provisional identity

verifyProvisionalIdentity

Verifies an attached provisional identity.

To be called when the status returned by attachProvisionalIdentity is IDENTITY_VERIFICATION_NEEDED.

function verifyProvisionalIdentity(verification: Verification): Promise<void>

Once the provisional identity is verified, every resource shared with it can now be decrypted by the user, who also joins every group in which the provisional identity was a member.

Parameters
verification: Verification A verification containing the provisional identity's email, and the verification code
Returns
Promise The promise is fulfilled once the verification is done
Throws
InvalidArgument The verification is ill-formed or incomplete
PreconditionFailed The status of the current session is not READY
PreconditionFailed The status of the attach result is not IDENTITY_VERIFICATION_NEEDED
ExpiredVerification The verification expired
InvalidVerification The verification is invalid
TooManyAttempts Too many verification attempts occurred. Please retry later.
NetworkError Network error, e.g. connection lost or the Tanker server is not reachable
DeviceRevoked The current device is already revoked and cannot be used anymore

Events

Tanker uses EventEmitter to emit events.

You can subscribe to events using on and unsubscribe using removeListener. Please refer to the EventEmitter documentation for more information.

statusChange

Emitted when the session status changes. The event takes the new status as a parameter.

tanker.on('statusChange', newStatus => console.log(`Tanker status has changed: ${newStatus}`));

deviceRevoked

Emitted when the current device has been revoked and cannot be used anymore. The revocation can be initiated on any device the user has registered, including the current device.

tanker.on('deviceRevoked', () => console.log('One of my devices is already revoked and cannot be used anymore'));

Utilities

Those functions are free functions exported by the Tanker package, they can be imported individually as follows:

import { toBase64, fromBase64, prehashPassword } from '@tanker/client-browser';
// or...
const { toBase64, fromBase64, prehashPassword } = require('@tanker/client-browser');

The encoding and decoding functions are convenience functions used internally by Tanker. They replace limited implementations provided by the different environments Tanker runs on.

Base64 to buffer

Converts an array of bytes to a base64-encoded JavaScript string and back. Those are typically used when sending and receiving text from the browser to a remote server:

function toBase64(bytes: Uint8Array): b64string
function fromBase64(str: b64string): Uint8Array
// Receive and decrypt
const encryptedText = api.receiveText();
const encryptedData = fromBase64(encryptedText);
const clearText = await tanker.decrypt(encryptedData);

// Encrypt and send
const encryptedData = await tanker.encrypt(clearText);
const encryptedText = toBase64(encryptedData);
api.sendText(encryptedText);

Note

Please note that JavaScript's atob() and btoa() are not suited to work with Uint8Array's and unicode data. more details on the mozilla website.

prehashPassword

Utility function to hash a password client side.

function prehashPassword(password: string): b64string

This function is only useful in the specific case described in the verification by passphrase guide.