Implement Custom Browser Authentication Client

The M-PIN protocol involves cryptographic operations over stored cryptographic material on the client side. This is the reason why the MIRACL Trust service provides a browser client for its authentication that handles all of that. It also handles enrolment, identity management and much more.

# Enable Custom Authentication Clients

To enable custom authentication clients, CORS requests should be allowed from the MIRACL Trust Portal. This is done by setting the Allowed CORS Domains property in your project’s settings to the domain where the web client is hosted.

# What is CORS

Browsers restrict cross-origin HTTP requests by default. This is done to prevent certain attacks. 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 provides a JavaScript library that aids the development of custom authentication clients - MIRACL Trust JS Client Library.

# Install the 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

const mcl = new MIRACLTrust({
  projectId: "<YOUR_PROJECT_ID>",
  seed: hexSeed,
  userStorage: localStorage,
  deviceName: deviceName,
  oidc: {
    client_id: "<YOUR_CLIENT_ID>",
    redirect_uri: "<YOUR_REDIRECT_URL>",
    response_type: "code",
    scope: "openid",
  },
  cors: true,
});

# Verify a End User

You can generate a verification link using 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 will look like this:

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

# Register a Device

In order to register the browser, you will first need to get an activation token using the getActivationToken method of the library and the received verificationURL:

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, you need to 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

You can check if the device has already been registered using the list method of the users storage object:

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

Depending on your requirements, you can only allow 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, you need to call the generateAuthCode method:

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

  // The code in the result needs to be exchanged
  // by your back end for a MIRACL Trust identity token
  console.log(result.code);
});

In order to verify the code in your back end and get the identity of the end user, you need to make the following request to api.mpin.io:

curl \
  --request POST \
  --data "grant_type=authorization_code&client_id=${YOUR_CLIENT_ID}&client_secret=${YOUR_CLIENT_SECRET}&code=${CODE}&redirect_uri=${YOUR_REDIRECT_URL}" /
  https://api.mpin.io/oidc/token

In the response, you get an id_token, which is a JWS that can be verified using the keys published on https://api.mpin.io/oidc/certs.

# Security

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