Node.js

This example provides a very simple partner application template based on Node.js. It helps you to understand the basic steps regarding application integration and how our authentication process works. It uses jsonwebtoken for verifying/signing JWTs and request-promise-native for requests.

Setup

Your package.json might look like this:

{
  "name": "nodejs-example",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "start": "node index.js"
  },
  "dependencies": {
    "jsonwebtoken": "8.5.1",
    "request": "2.34.0",
    "request-promise-native": "1.0.7"
  }
}

JWT signature verification

In order to verify our JWT's signature based on our stages you will need to download these public key files and put them beside your package.json:

365FarmNet_Connect-API_public_key_development.pem

365FarmNet_Connect-API_public_key_production.pem

Code

Create a file index.js and put this code into it:

const http = require('http');
const url = require('url');
const fs = require('fs');

const jwt = require('jsonwebtoken');
const rp = require('request-promise-native');

// developer partner credentials
const partner_id = '5726c2cf-143b-4834-aa54-24a1c1516a48';
const partner_secret = 'trsL26xTtFXgPHBJE8n4ZrN6R7fWfLrK';

http.createServer(function (req, res) {

  res.writeHead(200, { 'Content-Type': 'text/html' });

  const connect_token_jwt = getConnectTokenJwtFromUrl(req.url);

  if (connect_token_jwt == null) {
    res.end('No Connect-Token found, pass "jwt" as URL query parameter!');
    return;
  }

  const connect_token = jwt.decode(connect_token_jwt);
  const api_base = connect_token && connect_token['fn-ext'] && connect_token['fn-ext']['apiBase'] || null;

  if (api_base == null) {
    res.end(`The decoded Connect-Token seems strange '${connect_token}'. 'apiBase' expected!`);
    return;
  }

  const stage = api_base === 'https://connect.365farmnet.com' || api_base === 'https://pp-connect.365farmnet.com' ? 'production' : 'development';

  try {
    verifyConnectTokenJwt(connect_token_jwt, stage);
  } catch (e) {
    res.end('The Connect-Token is invalid: ' + JSON.stringify(e));
    return;
  }

  console.log('Your Connect-Token\'s content is: ' + JSON.stringify(connect_token));

  const partner_token_jwt = createPartnerTokenJwt(connect_token_jwt);

  if (partner_token_jwt == null) {
    res.end('Your Partner-Token could not be created. Check logs!');
    return;
  }

  getCompanyFromApi(api_base, partner_token_jwt).then(data => {
    res.end('OK: ' + JSON.stringify(data));
  }).catch(err => res.end('Error fetching data: ' + JSON.stringify(err)));
}).listen(3000);

function getConnectTokenJwtFromUrl(req_url) {
  const query = url.parse(req_url, true).query;
  return query.jwt || null;
}

function verifyConnectTokenJwt(connect_token_jwt, stage) {
  const public_key = fs.readFileSync('365FarmNet_Connect-API_public_key_' + stage + '.pem');
  return jwt.verify(connect_token_jwt, public_key, { clockTolerance: 10 }) || null;
}

function createPartnerTokenJwt(connect_token_jwt) {
  const payload = {
    con: connect_token_jwt,
    iss: partner_id
  };
  const options = {
    expiresIn: '1d',
    header: {
      ver: '0.1',
      type: 'partner'
    }
  };
  try {
    return jwt.sign(payload, partner_secret, options) || null;
  } catch (e) {
    console.log(e);
  }
}

function getCompanyFromApi(api_base, partner_token_jwt) {
  return rp({
    uri: `${api_base}/connect/v1/company`,
    headers: {
      Authorization: `Bearer ${partner_token_jwt}`
    }
  });
}

Run

Open your terminal, install the dependencies and start the application using either node or npm start. This will spawn a server listening for calls on port 3000. You can open your browser, navigate to localhost:3000 and should see No Connect-Token found, pass "jwt" as URL query parameter!.

Then navigate to our developer environment, register and set the URL to http://localhost:3000/. Since the example uses our developer credentials it should work out of the box and give your account information.