User Context and SDK Initialization

The IronWeb SDK must have the context of the person who is currently using your app before that user can access documents or interact with groups. Your code is responsible for providing the identity of the user currently authenticated by your app to the SDK.

User Verification

Your application provides this user identity to the IronWeb SDK using a JSON Web Token (JWT). This JWT asserts the identity of the user in a way that allows the IronCore system to verify that the information in the assertion is correct and that the assertion was generated by your system.

The JWT assertion is required every time the SDK is initialized.

Browser Session Creation

The first time a user visits your app and the initialize function is run, a new unique "master" public and private key pair is generated for the user. The private key of this key pair is required anytime the user wants to approve a browser or device for usage with the SDK. In order to simplify this process the user will provide a password that will be used to securely encrypt and store their private key within the IronCore database. This password is then required for subsequent devices that the user wants to approve to decrypt their content.

For a browser session, this password is required the first time the user is synced to IronCore as well as any subsequent times that the user wants to approve a new browser session for usage with the SDK. The users password will only be necessary if the user hasn't approved the current browser session, so it won't always have to be provided each time the initialize function is run.

IronWeb.initialize()

Initializes the IronWeb SDK and, if successful, sets the context of the user in the SDK, which allows all other document, group, and user methods to be called. If this method is called by a new user that doesn't yet have cryptographic keys, the SDK will automatically generate keys and store the information about the user with the IronCore system. On subsequent calls, initialize will verify the user. The initialize method must be called on every page load in order to set the proper user context.

IronWeb.initialize(jwtCallback, passwordCallback)

Parameters

Parameter Name Value Description
jwtCallback Function() => Promise<string> A function that returns a Promise that resolves with a valid JWT(string). The jwtCallback should make a call to your server and resolve with a JWT. This function will be called every time you invoke initialize.

JWT generation should not happen on the client.
passwordCallback Function(didUserExist) => Promise<string> A function that returns a Promise that resolves with a user's password. This password is used to authorize the current browser session. This method is invoked if the current browser session has not already been authorized.

The single Boolean parameter that is passed to the method denotes whether the user has already been synced to IronCore, or if this is the first initialization for this user.

Response

Returns a Promise that resolves with information about the currently initialized user. If the returned user information has the needsRotation flag set to true, then your code should immediately make a call to IronWeb.user.rotateMasterKey() to rotate the user's key before performing any other operation.

{
  "user": {
    "id": string,
    "status": number,
    "needsRotation": boolean
  }
}

IronWeb.isInitialized()

Returns a boolean that denotes whether the IronWeb SDK has been initialized and has a user context set.

IronWeb.isInitialized()

Response

Returns a boolean that denotes whether the SDK is currently authenticated with a user context.

IronWeb.createNewUser()

Manually sync a user record into IronWeb by providing a callback that will supply a valid JWT and the password to use to escrow the user's private key. This method is provided as an alternative to initialize. Unlike initialize, which automatically generates a device for the user if they do not exist, this method does not automatically generate a new device key set for the user. Once this method successfully completes, the user will be synced to IronCore but will still not be able to interact with documents or groups until they have generated a new set of device keys.

IronWeb.createNewUser(jwtCallback, password, options)

Parameters

Parameter Name Value Description
jwtCallback Function() => Promise<string> A function that returns a Promise that resolves with a valid JWT(string). The jwtCallback should make a call to your server and resolve with a JWT that asserts the identity of the currently authenticated user.

JWT generation should not happen on the client.
password string The password to use to escrow the private key for the user's account. This password will be required for any subsequent calls to initialize or createNewDeviceKeys.
[options.needsRotation] boolean Defaults to false. Set to true to flag that the private key for this user should be rotated to allow the user to "take control" of their keys. The main use case for this is a workflow that requires the users to be generated by someone else (such as a system administrator) prior to their first login. In this situation, a user's cryptographic identity is generated by a third party, like a server process, but the user can take control of their keys by rotating the private key using the user.rotateMasterKey() method. Once the rotation is complete, any copies of the user's private key that may have been retained by the person or system that generated the keys initially are no longer of any use.

Response

If successful this method will resolve with details about the newly synced user.

{
  "accountID": string,
  "segmentID": number,
  "status": number,
  "userMasterPublicKey": string,
}

IronWeb.createNewDeviceKeys()

Manually generate a new set of device keys for the user specified in the provided JWT. This method is an alternative to calling initialize, which automatically generates and stores a new set of device keys associated to the user. Unlike initialize, this method returns the device keys to the caller, who is responsible for storing them. The value returned from this method can be used to initialize any of the other IronCore SDKs.

IronWeb.createNewDeviceKeys(jwtCallback, password)

Parameters

Parameter Name Value Description
jwtCallback Function() => Promise<string> A function that returns a Promise that resolves with a valid JWT(string). The jwtCallback should make a call to your server and resolve with a JWT that asserts the identity of the currently authenticated user.

JWT generation should not happen on the client.
password string The password that was used when the user's account was created.

Response

If successful this method will resolve with details about the newly created device keys.

{
  "accountId": string,
  "segmentId": number,
  "devicePrivateKey": string,
  "signingPrivateKey": string,
}

Example

The following shows an example of how you would initialize the IronWeb SDK. This example assumes that you've already created an IronCore account and have your Project ID, Segment ID, and Identity Assertion key ID as well as a Identity Assertion private key in PEM file format.

The first part to implement is the server side JWT generation endpoint. The following example is an implementation in NodeJS using ExpressJS with the jsonwebtoken NPM package.

Server Side

const fs = require("fs");
//Import the jsonwebtoken library
const jwt = require("jsonwebtoken");

//Read in private key file contents
const identityAssertionKeyPrivateKey = fs.readFileSync("<PATH to key PEM file>", "utf8");

app.get("/generateJWT", (req, res) => {
    //We'll respond from this endpoint with a JWT in plaintext form
    res.type("text/plain");

    //The JWT payload is an object which contains the Project, Segment, and Identty Assertion Key IDs
    //to associate with this user.
    const jwtPayload = {
        //Your unique Project ID
        pid: PROJECT_ID,
        //Your Segment ID for this Project
        sid: "SEGMENT_ID",
        //Your Identity Assertion Key ID for this Project
        kid: IDENTITY_ASSERTION_KEY_ID,
    };

    const jwtToken = jwt.sign(jwtPayload, projectPrivateKey, {
        //Algorithm MUST be 'ES256' which is ECDSA using P-256 curve and SHA-256 hash algorithm
        algorithm: "ES256",
        //Token expire time. The IronCore server only supports a max of 2 minutes.
        expiresIn: "2m",
        //The JWT "subject" is the unique ID of the user who is currently
        //authenticated into your app. In NodeJS/Express this might be available
        //on the 'req.user' object
        subject: UNIQUE_ID_OF_CURRENTLY_LOGGED_IN_USER,
    });

    //Send the JWT back to the client
    res.send(jwtToken);
});

Client Side

Now that you have a server-side endpoint which will generate you a valid JWT for authenticated users in your system, you can now setup the initialize function within your client side JavaScript.

import {initialize, ErrorCodes, document} from "@ironcorelabs/ironweb";

/**
 * Request the endpoint on your server that we setup above. Since we setup the endpoint
 * above to return the token in plaintext, we need to parse the response as such.
 */
function getJWTForUser() {
    //The fetch() API returns a Promise which we can then chain to parse out
    //the plaintext content of the response, which will be a valid JWT.
    return fetch("/generateJWT").then((response) => {
        return response.text();
    });
}

/**
 * Request the users password. This function will only be called if the user
 * has not authorized this browser to access their data.
 */
function getUsersPassword(didUserExist) {
    //The `didUserExist` argument is a boolean parameter which gives you the opportunity
    //to alter the user experience for newly created/synced users.
    return new Promise((resolve, reject) => {
        const password = window.prompt("Please provide your secure password.");
        resolve(password);
    });
}

/**
 * Initialize the IronWeb SDK with the two provided callbacks. The Promise will resolve
 * once successful at which point the document/group/user methods are available to be
 * invoked
 */
initialize(getJWTForUser, getUsersPassword)
    .then((initResult) => {
        //initResult.user.id is the initialized user
        return document.list();
    })
    .then((userDocs) => {
        //Show user a list of their documents
    })
    .catch((sdkError) => {
        if (sdkError.code === ErrorCode.USER_PASSCODE_INCORRECT) {
            alert("Wrong password provided! Please try again");
        }
    });

Once you have successfully initialized the SDK you can then use it to implement the functionality required by your app via the different IronWeb SDK methods. The initialize method will need to be called upon every page refresh in your app, however the user will only need to provide their password once per session per browser they want to use.