Logout in: 0 min and 0 sec

Log In, Security JWT

To inhibit brute-force attacks, the ACCESS API requires a Proof-of-Work (POW) challenge to be solved before a JWT token is issued. The Proof-of-Work challenge is a SHA256 hash that must be solved by the client before the JWT token can be obtained.

The POW challenge is obtained by calling the following URL:

GET - https://rest.triand.com/Session/powChallenge

curl -X GET https://rest.triand.com/Session/powChallenge  \
     -H "Accept: application/json" 

 {"challenge":"eyJjb2InR...really long string...iYjdmZDcyxZiJ9"}

The response contains a challenge string that must be solved by the client. The client must solve the challenge by finding a solution that, when hashed with the challenge string, produces a hash that starts with a certain number of leading zeros. The POW challenge expires in two minutes.

Triand uses the NPM Javascript Package "hashcash" to implement POW. The Postman collection supplied above uses the following to solve the POW challenge:

const CryptoJS = require("crypto-js");
const ZEROES=4;
const zeroes = new Array(ZEROES).fill('0').join('');
const maxAttempts = 1000000

const b64StrPowChallenge = pm.response.json().challenge;              
pm.environment.set("powChallenge", b64StrPowChallenge);    // Store it as an environment variable

const strPowChallenge = CryptoJS.enc.Base64.parse(b64StrPowChallenge).toString(CryptoJS.enc.Utf8);
const objPowChallenge = JSON.parse(strPowChallenge).content;
const token = objPowChallenge.token;
const hardness = objPowChallenge.hardness;
const solutions = [];

function solveChallenge() {
    for(let i = 0; i < hardness; i++) {
        const solution = findZeroes(`${i}:${token}`);
        solutions.push(solution);
    }
    return CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(JSON.stringify(solutions))); 
}

function findZeroes(token){
    let attempt = 0;
    while (attempt < maxAttempts) {
        const value = `${attempt}:${token}`;
        const hash = CryptoJS.SHA512(value).toString();
        if(hash.substring(0, ZEROES) === zeroes) {
            return attempt.toString();
        }
        attempt++;
    }
}

let start = Date.now()
let solution = solveChallenge()
let end = Date.now()
let timeInMs = end - start;
let timeInSeconds = (timeInMs / 1000).toFixed(1);
console.log(`Time taken: ${timeInSeconds} seconds.  Solution: ${solution}`);

// Store the response in an environment variable
pm.environment.set("powSolution", solution); 

Depending upon the speed of your system generating the response will take between 1 and 6 seconds. Once you are logged in you will not need to repeat the POW solution again.

The client must then send the solution to the following URL to log in and obtain a JWT token:

POST - https://rest.triand.com/Session/login

The request body must contain the following parameters:

ParameterBusiness Rule / RegexDescription
email/w+/Login email or ActiveDirectoryId
password/w+/Login password
powChallenge/w+/Proof-of-Work Challenge
powSolution/w+/Solution to the Proof-of-Work Challenge

Example post and response:

curl -X POST https://rest.triand.com/Session/login  \
     -H "Accept: application/json" \
     -H "Content-Type: application/json" \
     -d '{   \
      "email": "{your email or ActiveDirectoryId}",   \
      "password": "{your password}",   \
      "powChallenge": "eyJjb2InR...really long string...iYjdmZDcyxZiJ9",   \
      "powSolution": "eyJjb23er...really long string...iawei"   \
    }'

{
  "params": {
    "actionOk":true,
    "error":[]
  },
  "timing":{
    "srvStart":"2025-06-14 01:24:11.372",
    "srvEnd":"2025-06-14 01:24:11.527",
    "srvMills":155
  },
  "jwt":"eyJ0eX...valid JWT token...sZNSf6Eitg",
  "frtTkn":"eyJ0eXAiO1QiLC...ignore this string...MSwianRpIJEK1nA"
}

The jwt in the response is used in following calls as the header "Authorization: Bearer ....."