Introduction

This is the official documentation of the Hushmesh API.

What is the Mesh?

The mesh is the "trust network". Much like social networks, the mesh enables digital interactions between people and organizations. But unlike traditional social networks, the mesh does not target a specific application or mode of communication. Rather, it is designed from the ground up as a neutral platform to enable digital trust and privacy as a service to all other applications, websites, services and devices, for everyone and every organization.

What you can do as a developer?

You can create applications in the portal and use the mesh for your usecases.

Mesh in

In order to make authorized calls to the Mesh, you must first obtain an access token. This section describes how to obtain such a token.

Before getting started, you need to create an app and configure a valid redirect URL. A registered HushMesh integration is assigned a unique Client ID and Client Secret which are needed for the OAuth2 flow.

Recommended way to autorize user to the mesh as a developer is by using our npm meshlib library.

Mesh in button

Include an init:

import { Auth } from '@hushmesh/meshlib'

const meshApi = new Auth({
  clientId: 'YOUR_CLIENT_ID',
  responseType: 'code',
  redirectUri: 'https://beta.hushsafe.com/auth',
  codeChallenge,
  codeChallengeMethod: 'S256',
  isPopup: true
})

If you are using any modern JavaScript framework, you can create mesh in button component and inside the component include and initialize mesh in library. You can install meshlib from npm and include it in your project.

Inside handler:

meshApi.meshin()

After that you just need to use mesh in method inside your onClick handler.

After successful mesh in you’re going to be redirected to the page, specified in the redirectUri.

How to generate code challenge and code verifier

Generate challenge data example

import CryptoJS from 'crypto-js'

const generateChallengeData = () => {
  const codeVerifier = CryptoJS.lib.WordArray.random(128).toString(CryptoJS.enc.Base64)
  const codeChallenge = CryptoJS.enc.Base64.stringify(sha256(codeVerifier)).replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_')
  return { codeVerifier, codeChallenge }
}

In order to get user tokens first you have to obtain the authorization code. Next you can exchange your authorization code and code verifier for tokens.

Exchange code to OAuth tokens

Token service example

import axios from 'axios'

const BASE_URL = 'https://api.hshm.sh/v0/getToken'
const CLIENT_ID = 'YOUR_CLIENT_ID'
const REDIRECT_URI = window.location.origin

const getTokens = (payload) => {
  const { code, codeVerifier } = payload

  const params = new URLSearchParams()
  params.append('client_id', CLIENT_ID)
  params.append('code_verifier', codeVerifier)
  params.append('grant_type', 'authorization_code')
  params.append('code', code)
  params.append('redirect_uri', encodeURIComponent(REDIRECT_URI))

  return axios.post(BASE_URL, params)
}

export default {
  getTokens
}

The last step is to exchange the code which you’re going to get back as query parameter in the URL and your initial code verifier to OAuth tokens.

Use token service

tokenService.getTokens(payload).then(res => {
  const accessToken = res.data.access_token
  const jwt = res.data.id_token
  let masterKey = ''

  if (jwt) {
    const tokens = jwt.split('.')
    const jwtObj = JSON.parse(atob(tokens[1]))
    masterKey = jwtObj.masterKey
  }
  // At this point you have accessToken
  // which should be used in Bearer authorization header
  // to access other Mesh API endpoints
})

Mesh in example for a simple HTML/JS page

Generate button

<button id="meshin-button" class="meshin-button">mesh in</button>
<script src="https://unpkg.com/@hushmesh/meshlib/dist/meshlib.js"></script>
const meshApi = new Meshlib.Auth({
  clientId: 'YOUR_CLIENT_ID',
  responseType: 'code',
  redirectUri: 'https://beta.hushsafe.com/auth',
  codeChallenge,
  codeChallengeMethod: 'S256',
})
const meshinButton = document.getElementById('meshin-button')
meshinButton.onclick = function(event) {
  meshApi.meshin()
}

You can find generated button code example for your application on your application page.

Button code contains three parts:

  1. HTML for your button. You can add your own CSS or apply any CSS classes from your framework.
  2. Script including tiny meshlib library to your application.
  3. Library initialization with your application parameters.

OAuth tokens

Object fields

Return object

{
   "access_token": "c8b6935c7e864315beeb959f0043a08d",
    "expires_in": 86364,
    "id_token": "eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiOWgyZmhmVVZ1UzlqWjh1VmJoVjN2QzVBV1gzOUlWVVciXSwiZXhwIjoxNTkxMjc1ODQzLCJpYXQiOjE1OTEyNTc1ODMsImlzcyI6Imh0dHBzOi8vYXBpLmhzaG0uc2giLCJqdGkiOiI5aDJmaGZVVnVTOWpaOHVWYmhWM3ZDNUFXWDM5SVZVVy0wZXRyYmx2OE1rdUQ5VDk4QUtja1pnejdRcGhWRHFwUyIsIm1hc3RlcktleSI6IlFRT1kyQ25vRmlknnZ4aWVRbzh0azdBZFlCbmdMb2I0Iiwic3ViIjoiOWgyZmhmVVZ1UzlqWjh1VmJoVjN2QzVBV1gzOUlWVVctMGV0cmJsdjhNa3VEOVQ5OEFLY2taZ3o3UXBoVkRxcFMifQ._OhQZUnsN-vd31COikcqWr_YlyPhQju4wEZLRgd_QS8EqvdTPTaMI0Ww-aNVhuTKQ09fY41jiwVNgm979t0RTkelR1gM1fFmKhyFVp3uoUUDOg95SmqQS69QzSzNGPym",
   "refresh_token": "333a5730763f447594e08869401ffe22",
    "scope": "",
    "token_type": "Bearer"
}

After the exchange your authorization code and code verifier for tokens you’re going to receive an object with few fields:

Field Description
access_token Access token to use to access Mesh API.
expires_in When current token going to be expired.
id_token JWT token which contains your masterKey.
refresh_token Refresh token can be used for tokens update without additional login.
token_type Token type. Currently Bearer only.

Two most important pieces of information here are:

access_token — token which you have to use to access any Mesh API in the authorization header (without it you’re going to have 401 error — anautorized).

id_token — it’s JWT token, which contains information in it’s body. The most important part is unique masterKey, which can be used for different usecases (for example, as a key for your encryption/decryption process). To learn more about id_token structure you may want to take a look at our token viewer.

Parsing masterKey

parse masterKey

const idToken = 'your_id_token_here'
const parts = idToken.split('.')
const jwtObj = JSON.parse(atob(parts[1]))
const masterKey = jwtObj.masterKey

This sample shows how to parse masterKey from id_token:

Application example

In this section we are going to explore simple application hushsafe.com that demonstrates the unique security capabilities enabled by the mesh.

We are going to use mesh in button and auth experience, getting user’s data and to use storage API.

Application stack

Hushsafe is single page application, stack we are using:

App registration

First step for any mesh application should be app registration in relying parties tool. Mesh in in the tool and you’re going be able to create and manage your applications.

Mesh in button

Example:

import { Auth } from '@hushmesh/meshlib'
import crypto from '@/services/crypto'

const { codeChallenge, codeVerifier } = crypto.generateChallengeData()

const meshApi = new Auth({
  clientId: '9h2fhfUVuS9jZ8uVbhV3vC5AWX39IVUW',
  responseType: 'code',
  redirectUri: window.location.origin + '/callback',
  codeChallenge,
  codeChallengeMethod: 'S256',
  isPopup: true
})

// Inside click handler
meshApi.meshin()

After successful app registration we can copy Mesh in button code example from our application page in relying parties tool.

You can find all information about mesh in button in mesh in section.

On Hushsafe.com we are using exactly the approach from the mesh in section.

Callback page

Example

mounted () {
  if (window.opener) {
    window.opener.location.href = window.location.origin + '/auth' + window.location.search
    window.close()
  } else {
    window.location.href = window.location.origin + '/auth' + window.location.search
  }
}

On Hushsafe.com we’re using our default mesh in experience with QR code popup, because of that we need callback page which can close the popup and redirect to the app auth page (which responsible for the exchange of the code for tokens).

Callback page should be specified as redirectUri. Url going to have query string with exchange code which you should use to exchange code to the tokens.

https://hushsafe.com/auth?access_token=code=your_exchange_code

From this url we are grabbing code and providing it to auth page.

Auth page

Example

mounted () {
  const code = this.$route.query.code
  const codeVerifier = sessionStorage.getItem('code_verifier')

  this.$store.dispatch('user/getTokens', { code, codeVerifier })
    .then(() => {
      // success, at this point we have tokens
      // and can use any Mesh API
      // userinfo in this example
      this.$store.dispatch('user/getUserData')
    })
    .catch((err) => {
      // error
    })
}

At this point we already have code to exchange it to tokens, so the main goal of the page is to make api call to get tokens and depends on the results go to another route(on success) or show error message on error.

To learn more about token exchange see Exchange code to OAuth tokens.

Getting user's info

import axios from 'axios'
import store from '@/store'

const BASE_URL = 'https://api.hshm.sh/v0/userinfo'
const axiosConfig = {}

// here we're setting received token to axios header
const setHeaders = () => {
  const accessToken = store.getters['user/accessToken']
  if (accessToken) {
    axiosConfig.headers = {
      Authorization: `Bearer ${accessToken}`
    }
  }
}

const getUserData = () => {
  // Fetching user data like name, email etc.
  setHeaders()
  return axios.get(BASE_URL, axiosConfig)
}

export default {
  getUserData
}

If nesessary, at this point we can get meshid in user’s info with userinfo api. This step is optional and you may skip it if you don’t need user’s info but only would like to use storage api.

Encryption

Crypto.js example

import encUTF8 from 'crypto-js/enc-utf8'
import AES from 'crypto-js/aes'
import store from '@/store'

const encrypt = value => {
  // To encrypt/decrypt values we are using user's master key
  const secret = store.getters['user/masterKey']
  return AES.encrypt(value, secret).toString()
}

const decrypt = value => {
  const secret = store.getters['user/masterKey']
  return AES.decrypt(value, secret).toString(encUTF8)
}

export default {
  encrypt,
  decrypt
}

We don’t want to send unencrypted data, so we should prepare a solution to encrypt/decrypt data. Here we’re using crypto.js library and our masterkey as a secret.

Fetch and store data

Storage API usage

import axios from 'axios'
import store from '@/store'

const BASE_URL = 'https://api.hshm.sh/v0/storage'

const setHeaders = () => {
  const axiosConfig = { headers: {} }
  const accessToken = store.getters['user/accessToken']
  if (accessToken) {
    axiosConfig.headers = {
      Authorization: `Bearer ${accessToken}`
    }
  }
  return axiosConfig
}

const fetchData = id => {
  // To fetch data you're going to need an object id you've created before
  // You can also get all object ids available for user
  // by GET request to BASE_URL
  const config = setHeaders()
  return axios.get(`${BASE_URL}/${id}`, config)
}

const storeData = (id, data) => {
  // To store the data you have to provide object id
  // and data which can be any format including binary
  const config = setHeaders()
  config.headers['Content-Type'] = 'application/json'
  return axios.post(`${BASE_URL}/${id}`, data, config)
}

export default {
  fetchData,
  storeData
}

Now we can use Storage API to save and fetch data.

Save data

Keycard example

{
  "id": "D00g0sxZ",
  "title": "Keycard Title",
  "data": "U2FsdGVkX19Sm+yIbQYNf1cetF14oA62KU97GCmFU3Y=",
  "createdAt": "2020-03-12T15:33:00.909Z"
}

To save data we should provide object id. In case of hushsafe we want to store user’s keycards, so let’s call it "keycards". Our full endpoint going to be https://api.hshm.sh/v0/storage/keycards

You free to decide what format do you want to use. In our case each keycard has four fields: id, title, data, createdAt.

As you can see, our data is encrypted with crypto.js.

Fetch and delete data

To fetch data back we’re going to use the same endpoint but GET request, or DELETE request for deleting https://api.hshm.sh/v0/storage/keycards

Storage API docs

Object IDs available to a user

Example

  GET https://api.hshm.sh/v0/storage

In case you want to get all object ids meshedin user has an access, you can do it by sending request to:

GET api.hshm.sh/v0/storage

Storage API

Get object IDs

Example

  GET https://api.hshm.sh/v0/storage

GET api.hshm.sh/v0/storage

— lists object IDs for the meshed in user.

Return object

{
   "statusCode": 200,
   "statusDescription": "Success",
   "objectIds": ["id1", "id2"]
}

Store data

Example

  POST https://api.hshm.sh/v0/storage/some_id
  body: {"title": "data"}

POST api.hshm.sh/v0/storage/{object_id}

— store arbitrary data for the meshed in user.

Return object

{
   "statusCode": 200,
   "statusDescription": "Success"
}
Name Type Required Description
object_id String Yes The ID of the stored data

Get stored data

Example

  GET https://api.hshm.sh/v0/storage/some_id

GET api.hshm.sh/v0/storage/{object_id}

— fetches data that was stored for the meshed in user.

The data in the same format user stored previously.

Name Type Required Description
object_id String Yes The ID of the stored data

Delete stored data

Example

  DELETE https://api.hshm.sh/v0/storage/some_id

DELETE api.hshm.sh/v0/storage/{object_id}

— deletes data that was stored for the meshed in user.

Return object

{
   "statusCode": 200,
   "statusDescription": "Success"
}
Name Type Required Description
object_id String Yes The ID of the stored data

User info

Example

  https://api.hshm.sh/v0/userinfo

GET api.hshm.sh/v0/userinfo

— retrieves user info for the access token.

Return object

{
   "sub": "abc",
   "Name": "Alice",
   "Email": "alice@hushmesh.net"
}

Mesh out

Header example

Header example

axiosConfig.headers = {
  Authorization: `Bearer [YOUR_TOKEN]`
}

To finish authorized access to the Mesh, you should use mesh out API. It is a simple GET call to /logout endpoint.

Please make sure to provide usual Bearer Authorization header, otherwise it is not going to work.

Meshlib

Mesh out with meshlib

  import meshlib from '@hushmesh/meshlib'

  // in the handler:
  meshlib.meshout(accessToken)

If you are already using our meshlib library, you can just use meshout method out of the box.

Don’t forget to provide a valid access token as an argument.

Meshout API

Example

  https://api.hshm.sh/v0/logout

GET api.hshm.sh/v0/logout

— finishes Mesh session.

Return object

{
   "statusCode": 200,
   "statusDescription": "Success"
}

Browser extension

If you’re developing a browser extension most of the information related to web application going to be relevant. The main difference going to be mesh in experience. We’re going to cover all differences in this section — we’re going to use Chrome browser as an example.

Identity API

Identity API:

<script>
  const getAuthUrl = (options) => {
    const BASE_URL = 'https://api.hshm.sh/v0/init'
    const { responseType, clientId, redirectUri } = options
    const url = `${BASE_URL}?&response_type=${responseType}&client_id=${clientId}&redirect_uri=` + encodeURIComponent(redirectUri)
    return url
  }

  const meshin = () => {
    const { codeChallenge, codeVerifier } = generateChallengeData()
    return new Promise((resolve, reject) => {
      const redirectUri = chrome.identity.getRedirectURL()
      const url = getAuthUrl({
        clientId: 'YOUR_APP_CLIENT_ID',
        responseType: 'code',
        redirectUri,
        codeChallenge,
        codeChallengeMethod: 'S256',
      })

      chrome.identity.launchWebAuthFlow({
        url,
        interactive: true,
      }, (res) => {
        const code = getUrlParameter('code', res)

        // From there logic is exactly the same as for web app
        if (code) {
          tokenApi.getTokens({ code, codeVerifier }).then((res) => {
            const accessToken = res.data.access_token
            const jwt = res.data.id_token
            let masterKey = ''
            if (jwt) {
              const parts = jwt.split('.')
              const jwtObj = JSON.parse(atob(parts[1]))
              masterKey = jwtObj.masterKey
            }
            resolve({ accessToken, masterKey })
          }).catch((err) => {
            reject(err)
          })
        } else {
          reject(res)
        }
      })
    })
  }
</script>

In browser extensions we cannot use the same callback flow as per web applications. Usually your browser extension will have url similar to chrome-extension://npmgajiaihfjibkgojndemlehpalicjc/home.html and we cannot open such url as a callback because of security restrictions.

Instead of the callback we should use browser’s identity API and receive our tokens information in the response.

Let’w walk through the code example:

Caveats

To store tokens and masterKey it’s better to use your extension background. If you’re going to put them in the popup, they’re going to be cleared every time user is closing popup.

Errors

The HTTP error codes returned:

Code Description
400 Missing/invalid fields in the request
401 Unauthorized, additional credentials needed
403 Permission denied
404 Resource not found
406 Unhandled message type
409 Conflict
500 Internal server error

Not finding the information you need?

Contact us info@mesh.in

Last updated Aug 13, 2020

© 2019–2020 Hushmesh Inc., a Delaware Public Benefit Corporation