GET https://api.yubico.com/wsapi/2.0/verify?otp=__YOUR_YUBICO_OTP__
const crypto = require('crypto-js'),
yubiId = pm.variables.get('YUBI_ID'),
yubiKey = pm.variables.get('YUBI_KEY'),
secretKey = crypto.enc.Base64.parse(yubiKey),
generatedNonce = crypto.lib.WordArray.random(10).toString(crypto.enc.Hex);
pm.request.url.query.upsert({ key: 'id', value: yubiId });
pm.request.url.query.upsert({ key: 'nonce', value: generatedNonce });
/**
* Convert the Postman PropertyList to a standard JS Array
* in order to avoid error:
* "TypeError: queryParams.sort is not a function"
* because pm.request.url.query is not a standard JavaScript array.
* It is a Postman-specific object called a PropertyList
*/
const queryParams = pm.request.url.query.all();
const result = queryParams
.filter(p => p.key && p.value && p.key !== 'h')
.sort((a, b) => (a.key < b.key ? -1 : (a.key > b.key ? 1 : 0)))
.map(item => `${item.key}=${item.value}`)
.join('&');
const hash = crypto.HmacSHA1(result, secretKey);
const signature = hash.toString(crypto.enc.Base64);
pm.request.url.query.upsert({ key: 'h', value: signature });
console.clear();
console.log(result, signature);
const responseText = pm.response.text(),
parsedResponse = {},
otpReq = pm.request.url.query.get('otp');
// Split by newlines (\r\n or \n) after trimming any outer spacing
responseText.trim().split(/\r?\n/).forEach(line => {
if (!line) return; // Skip any accidental empty lines
const parts = line.split('='); // Split by '='
// Grab the very first item as the key
const key = parts.shift().trim();
// Re-join the rest with '=' in case the value contained an '=' (like Base64 'h')
const value = parts.join('=').trim();
parsedResponse[key] = value;
});
const otpResp = parsedResponse.otp || '';
pm.test('Status code is 200', () => pm.response.code === 200);
pm.test(`OTP is the same provided in the request: ${otpReq}`, function () {
pm.expect(otpResp).to.eql(otpReq);
});
pm.test('OTP Status should be OK', function () {
pm.expect(parsedResponse.status).to.eql('OK');
});