Skip to content

Build a Secure Auth Token Server

Chris edited this page Nov 18, 2019 · 12 revisions

Intro

This how-to covers how to build an authentication server to get a token from RevOps using Node and express.js.

When we are finished it should work like this: Auth Server flow

Pre-flight Checklist

  • Node/NPM installed
  • your public/private key from your RevOps instance at /integrations/api/key
  • about 10 mins

Step 0 - Building the Server

This provides step by step instruction on how to build our Example Server

  1. Navigate to a new directory
  2. Run npm init --yes from the command line
  3. Then run npm install express cors request
  4. Create a new file named index.js
  5. Copy the following to index.js to create the server application
const express = require('express')
const cors = require('cors')
const request = require('request')

const port = 5000 // this can be whichever port is open

const key = process.env.KEY // this is an environment variable that is used to set your API key

let app = express()

app.use(cors())

app.listen(port, function () {
  console.log(`Web server listening on port ${port}`)
})
  1. Then define the route on the server
    • this examples defined the token route but can be defined as needed
/**
 * This defines an endpoint that we can request from the application to get an
 * access token. This token can be used to access RevOps resources.
 */
app.get('/token', function (req, res, next) {
  // this is only a warning if you forget to set the KEY enviroment variable
  if(!!key === false){
    console.warn("Cannot get token. No key is set.")
  }

  let searchParams = new URLSearchParams({
    accountId: req.query.accountId,
  })

  const url = `https://vault.revops.io/token?${searchParams.toString()}`

  const options = {
    url: url,
    method: 'GET',
    mode: 'cors',
    headers: {
      'Authorization': 'Bearer ' + key,
      'Accept': 'application/json',
      'Content-Type': 'application/json;charset=UTF-8',
    },
  };

  request(options, function (error, response, body) {
    if (!error && response.statusCode == 200) {
      const token_response = JSON.parse(body)
      res.json({access_token: token_response.access_token})
    } else {
      res.json({access_token: false}) // if we have an error return a falsey value, typically false
    }
  });
})
  1. Run the server using KEY=sk_sandbox_<your_key> node index.js
    • your public key can be used to get a token but its scope will be limited

Now your server will be running on port 5000, or the port of your choosing.

Step 1 - Integrating with the Client Application

Next, let's define a callback function for getting it from the server. It takes an accountId as an argument and returns a token and will be called when necessary.

/**
 * getToken() calls our example auth server with an accountId 
 * to produce an authorization token that can be used to view and 
 * manipulate the account. The RevOps components will make the 
 * appropriate calls to it using the accountId or '*' when necessary.
 */
getToken = async (accountId) => {
  const searchParams = new URLSearchParams({
    accountId: accountId,
  })

  const options = {
    method: 'GET',
    mode: 'cors',
  };

  const url = `http://localhost:5000/token?${searchParams.toString()}`
  const response = await fetch(url, options)
  const responseOK = response && response.ok
  if (responseOK) {
    const data = await response.json()
    if (!!data.access_token === true) {
      this.setState({ accessToken: data.access_token })
      return data.access_token
    } else {
      console.warn("Unable to get token for requested operation.")
      return false
    }
  }

There are a few key insights here:

  1. The returned payload must preserve the access_token property of the JSON payload
  2. The function is asynchronous
  3. The callback must take and then use an accountId that is passed to it. Revops.js knows which parameters to pass based on the operation.

Next, we define a callback for the <PaymentMethod /> component that takes an

<PaymentMethod
  getToken={this.getToken} // this tell revops.js how to get the token from your server
  apiOptions={{
    loggingLevel: "error", // "warning" // "log"
  }}
  account={{
    accountId: "your-account-id",
    email: this.state.email,
  }}
  methods={['credit-card', 'ach', 'plaid']}
/>

Step 3 - Testing

Now we can run a quick test using CURL

$> curl 'http://localhost:5000/token?accountId=*'

We should see a payload that looks like this:

{
 "access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJodHRwczovL3ZhdWx0LnJldm9wcy5pbyI6eyJhY2NvdW50X2lkIjoiKiIsIm9yZ2FuaXphdGlvbl9pZCI6InJldm9wcy1pbyIsImlzX3NhbmRib3giOnRydWUsImlzX2FwaV91c2VyIjp0cnVlLCJpc19wdWJsaWMiOnRydWUsImFwaV9pbnRlcm5hbF9pZCI6InB1YmxpY0tleVNhbmRib3gifSwiaXNzIjoiaHR0cHM6Ly9yZXZvcHMuYXV0aDAuY29tLyIsInN1YiI6Im82Tmk3aVd0Z1padU9lbm4xVDBiVVJkQzZZdGRjd2o5QGNsaWVudHMiLCJhdWQiOiJodHRwczovL3ZhdWx0LnJldm9wcy5pb0BwdWJsaWMiLCJpYXQiOjE1NzI0MDkyOTAsImV4cCI6MTU3MjQwOTI5MCwiYXpwIjoibzZOaTdpV3RnWlp1T2VubjFUMGJVUmRDNll0ZGN3ajkiLCJzY29wZSI6ImFjY291bnRzOmxpc3Q6cHV0IGFjY291bnRzOmxpc3Q6cG9zdCIsImd0eSI6ImNsaWVudC1jcmVkZW50aWFscyJ9.z5--Ed8ks6y2N7dbeAr0yJrgXb47PQUC7WKqJGysYE8"
}

You may also want to decode the JWT using https://jwt.io/

Wrapping up

Alright, you did it! You built a server that can securely get a token to communicate with RevOps.