Implement Custom Browser Authentication Client

The M-PIN protocol involves cryptographic operations over stored cryptographic material on the client side. That’s why the MIRACL Trust service provides a browser client for its authentication that handles all of that, as well as enrolment, identity management and much more.

# Enable Custom Authentication Clients

To enable custom authentication clients, you must allow cross-origin resource sharing (CORS) requests. To do this:

  1. Go to your project’s settings in the MIRACL Trust Portal.
  2. Set the Allowed CORS Origins property to the domain where the web client is hosted.

# What is CORS

To prevent certain attacks, browsers restrict cross-origin HTTP requests by default. This means that by default a web application can only request resources from the same domain the application is running on. Cross-origin resource sharing (CORS) is an HTTP-header-based mechanism that allows restricted resources to be accessed from a domain different from the requesting one. It relies on the “preflight” request that the browser makes to check if the server permits the actual request using headers that indicate the HTTP method and headers of the actual request. If the resource is allowed for the requesting domain, the server response contains the Access-Control-Allow-Origin header with the value of the requesting domain.

# Custom Authentication Page

The MIRACL Trust platform supports custom web authentication clients. This gives you the freedom to implement it the way it best suits your use case. MIRACL Trust provides a JavaScript library that aids the development of custom authentication clients - MIRACL Trust JS Client Library.

# Install the Library

To install the JavaScript Library:

npm install --save @miracl/client-js

You can include the library in your build toolchain or use the pre-built browser version located in the /dist/client.min.js directory. You can find the reference for the library here.

# Configure an Instance of the MIRACL Trust Client

Use this code to configure your MIRACL Trust Client:

const mcl = new MIRACLTrust({
  projectId: "<YOUR_PROJECT_ID>",
  seed: hexSeed,
  userStorage: localStorage,
  deviceName: deviceName,
  cors: true,
});

# Verify an End User

To generate a verification link, use the POST /verification endpoint of the MIRACL Trust platform:

curl \
  --request POST \
  --user "${YOUR_CLIENT_ID}:${YOUR_CLIENT_SECRET}"
  --data '{
    "userId": "'"${USER_ID}"'",
    "deviceName": "'"${DEVICE_NAME}"'",
    "clientId": "'"${YOUR_CLIENT_ID}"'",
    "redirectURI": "'"${YOUR_REDIRECT_URI}"'",
    "expiration": "'"${EXPIRATION}"'",
    "scope": ["openid", "email"],
    "delivery": "no"
  }' \
  https://api.mpin.io/verification

The response looks like this:

{
  "verificationURL": "https://yourdomain.com/verification/confirmation?userId=alice@miracl.com&code=theVerificationCode"
}

# Register a Device

To register the browser, get an activation token using the getActivationToken method of the library and the received verification URL:

mcl.getActivationToken(
  "https://yourdomain.com/verification/confirmation?userId=alice@miracl.com&code=theVerificationCode",
  function callback(err, result) {
    if (err) {
      // Handle any potential errors
    }

    console.log(result.actToken);
  },
);

To finish the registration, call the register method using the received activation token (actToken):

mcl.register(
  userId,
  actToken,
  function (passPin) {
    // Here you need to prompt the user for their PIN
    // and then call the passPin argument with the value
    passPin(pin);
  },
  function callback(err) {
    if (err) {
      // Handle any potential errors
    }
  },
);

# Check if a Device Is Registered

To check if the device has already been registered, use the list method of the users storage object:

const allUsers = mcl.users.list();
console.log(allUsers);

Depending on your requirements, you can allow only one end user on the device or present the end user with an option to choose one of the registered User IDs.

# Authenticate

To authenticate, call the authenticate method:

mcl.authenticate(userId, pin, function callback(err, result) {
  if (err) {
    // Handle any potential errors
  }

  // The JWT in the result needs to be verified by your back end
  // to ensure that the authentication was successful
  console.log(result.jwt);
});

In the response, you get a signed JWT, which must be verified using the keys published in https://api.mpin.io/.well-known/jwks.

# Sign

Use the following code to produce a signature:

mcl.sign(
  userId,
  pin,
  documentHash,
  documentTimestamp,
  function callback(err, signature) {
    if (err) {
      // Handle any potential errors
      return;
    }
    console.log(signature);
  },
);

# Security

The authentication client is a standard JavaScript application that runs in the browser. This means it is susceptible to all potential vulnerabilities arising from that. Therefore, when implementing custom clients, it is important to have protection against such vulnerabilities as XSS, CSRF, etc.

# Content Security Policy

If you have Content Security Policy (CSP), add the following in your connect-src:

Content-Security-Policy: connect-src https://*.mpin.io;

This makes it possible for requests to be sent to the MIRACL Trust API https://api.mpin.io. We recommend keeping the * and not replacing it with api in the connect-src, because requests are sent to other subdomains during registration.