i think <@U29QCJQF3> was the last person who asked...
# suitescript
b
i think @michoel was the last person who asked here
s
You mean he used it ?
b
he asked the same question. im not sure if he found answers
👍 1
m
@samyt I did, using crypto.js and copied the jwt logic from node-jwt-simple (https://github.com/hokaccha/node-jwt-simple) For crypto.js I found this version converted to AMD - https://github.com/mark-keaton/oauth-netsuite/blob/master/cryptojs.js though @battk did point out after that the actual library is now a packaged as a universal library so it might work out of the box.
Here's my actual code (it's TypeScript)
Copy code
import * as crypto from './crypto';

export default function encodeJWT_HS256(payload, secret) {
  const header = {
    alg: 'HS256',
    typ: 'JWT',
  };

  const segments = [];
  segments.push(base64UrlEncode(JSON.stringify(header)));
  segments.push(base64UrlEncode(JSON.stringify(payload)));
  segments.push(signHS256(segments.join('.'), secret));
  return segments.join('.');
}

function base64UrlEncode(string) {
  const wordArray = crypto.enc.Utf8.parse(string);
  const base64 = crypto.enc.Base64.stringify(wordArray);
  return base64UrlEscape(base64);
}

function base64UrlEscape(string) {
  return string
    .replace(/\+/g, '-')
    .replace(/\//g, '_')
    .replace(/=/g, '');
}

function signHS256(input, secret) {
  const hash = crypto.HmacSHA256(input, secret);
  const base64 = crypto.enc.Base64.stringify(hash);
  return base64UrlEscape(base64);
}
s
Thanks You @michoel
m
BTW I've improved this code a bit (added decode/verify, support for additional algorithms)
Copy code
// Very simple JWT encoder based loosely on node-jwt-simple

// <https://github.com/hokaccha/node-jwt-simple>

import * as crypto from './crypto-js.min';

const algorithmFunctionMap = {
  HS256: crypto.HmacSHA256,
  HS384: crypto.HmacSHA384,
  HS512: crypto.HmacSHA512,
};

export function encode(payload, secret, algorithm = 'HS256') {
  const header = {
    alg: algorithm,
    typ: 'JWT',
  };

  const segments = [];
  segments.push(base64UrlEncode(JSON.stringify(header)));
  segments.push(base64UrlEncode(JSON.stringify(payload)));
  segments.push(sign(segments.join('.'), secret, algorithm));
  return segments.join('.');
}

export function decode(token, secret) {
  if (!token) {
    throw new Error('No token supplied');
  }

  const segments = token.split('.');
  if (segments.length !== 3) {
    throw new Error('Not enough or too many segments');
  }

  const headerSeg = segments[0];
  const payloadSeg = segments[1];
  const signatureSeg = segments[2];

  const header = JSON.parse(base64UrlDecode(headerSeg));
  const payload = JSON.parse(base64UrlDecode(payloadSeg));

  const signingInput = [headerSeg, payloadSeg].join('.');

  if (signatureSeg !== sign(signingInput, secret, header.alg)) {
    throw new Error('Signature verification failed');
  }

  if (payload.nbf && Date.now() < payload.nbf * 1000) {
    throw new Error('Token not yet active');
  }

  if (payload.exp && Date.now() > payload.exp * 1000) {
    throw new Error('Token expired');
  }

  return payload;
}

function sign(input, secret, algorithm) {
  const cryptoFunction = algorithmFunctionMap[algorithm];
  if (!cryptoFunction) {
    throw new Error('Algorithm not supported');
  }

  const hash = cryptoFunction(input, secret);
  const base64 = crypto.enc.Base64.stringify(hash);
  return base64UrlEscape(base64);
}

function base64UrlDecode(str) {
  const unescaped = base64UrlUnescape(str);
  const words = crypto.enc.Base64.parse(unescaped);
  return crypto.enc.Utf8.stringify(words);
}

function base64UrlUnescape(str) {
  str += new Array(5 - (str.length % 4)).join('=');
  return str.replace(/\-/g, '+').replace(/_/g, '/');
}

function base64UrlEncode(string) {
  const wordArray = crypto.enc.Utf8.parse(string);
  const base64 = crypto.enc.Base64.stringify(wordArray);
  return base64UrlEscape(base64);
}

function base64UrlEscape(string) {
  return string
    .replace(/\+/g, '-')
    .replace(/\//g, '_')
    .replace(/=/g, '');
}
Ended up using this as the crypto-js library file