Clause Developer Portal

Connect your agreements to the world.

Get Started    API Reference



Cross-origin resource sharing (CORS)

To protect Clause users from malicious users we prohibit direct use of the Clause API from browser-based applications. All Clause API requests should be made from a server otherwise they will be blocked by our CORS policy. Client-side applications can use a local proxy server to interact with Clause. Please see our sample app for guidance.

Clause uses the OAuth 2.0 protocol to allow a user to grant limited access to Clause to another site or system without exposing the user's Clause credentials.

By completing an OAuth authentication flow, we will provide a time and scope-limited JSON web token (JWT). A JWT can then be used to access Clause resources.

This guide describes the process for allowing a user of your application to exchange their Clause credentials for a JWT.

1. Getting a Client ID

Every application that accesses the Clause API needs to have a unique idenitifer. This helps users to identify your application when they are deciding if they are comfortable granting access to their data. The unique identifier is called the Client ID. You can generate a Client ID from the Developers settings page once you've logged into Clause Hub.

Developer Settings Page on Clause Hub

2. Getting a verifier and code challenge

To help prevent man-in-the-middle (MitM) attacks, applications that access the Clause API are required to generate a secret that can be used to verify their identity between each phase of the authentication flow. This secret is never shared with anyone else and is unique for each authentication request. This OAuth extension is referred to as Proof Key for Code Exchange (PKCE, pronounced pixie).

We provide some code samples below to help you to generate this secret code, called the verifier.

Using the verifier generator utility found on GitHub, generate an OAuth verifier.

const crypto = require('crypto');
const encode = buffer => buffer.toString('base64')
  .replace(/\+/g, '-')
  .replace(/\//g, '_')
  .replace(/=/g, '');
const verifier = encode(crypto.randomBytes(32));

Next, we'll generate a cryptographic hash of the verifier which we call the challenge. It is only the challenge that is sent to the Clause authorization server.

Using the challenge generator utility found here, and the verifier value from above, generate an OAuth challenge.

// input verifier
  const crypto = require('crypto');
  const encode = buffer => buffer.toString('base64')
    .replace(/\+/g, '-')
    .replace(/\//g, '_')
    .replace(/=/g, '');
  const challenge = encode(

3. Log in as a Clause user

Next, your application needs to redirect the user to the Clause login page. The URL of the login page must provide the following query parameters. Where CLIENT_ID, REDIRECT_URI and CHALLENGE are substituted for real values.

The REDIRECT_URI is a web page that you control that is capable of extracting a value from the query path of the page.

The user will then be prompted to enter their credentials to Clause, and if they haven't previously done so, to approve that they want to give your application access to their data.

When the user login succeeds, they will be redirected to the redirect_uri. For example:


4. Exchanging the code for a JWT

Use the code query variable and the token retrieval utility found here to retrieve a JWT.

// input client_id, verifier, code, redirect_uri
  const request = require('request');
  const querystring = require('querystring');

  const body = querystring.stringify({
    grant_type: 'authorization_code',
    code_verifier: verifier,

  return request({
    uri: '',
    method: 'POST',
    headers: {
      'Content-Length': body.length,
      'Content-Type': 'application/x-www-form-urlencoded'
  }, (error, {statusCode = 500, body = null}) => {
    // handle error and statusCode !== 2xx
    const {access_token, refresh_token} = JSON.parse(body);

    console.log(`access_token: ${access_token}`);
    console.log(`refresh_token: ${refresh_token || '(not in scope)'}`);

If everything is correct, you'll find the JWT in the access_token part of the response.

       "access_token": "eyJ0eXAiOiJKV1QiLCJ**************BaKqQUmUypwGxNf1SjOw",
       "expires_in": 86400,
       "token_type": "Bearer"

You can use then use the access_token in the Authentication header of all requests you send to the API.

Authorization: Bearer <<token>>
  Content-Type: application/json

You can also use the access_token in the Clause API reference docs to test the API from your browser.

5. Optional. Refreshing a JWT

As you can see from the JWT response above, each token is time-limited. In some scenarios you may want to keep a user's session open for longer than the time-limit of the token. This is achieved with a refresh token.

To get a refresh token in the first place, change the scope in the user login URL above from write:all to write:all offline_access. This will result in a JWT and a refresh token being returned by the token retrievel tool above.


Keep refresh tokens secret!

A refresh token lets an application keep a session open with Clause indefinitely by continually exchanging an refresh_token for a new access_token and refresh_token. This is very helpful when the user is not present (such as in a server-side application), but is dangerous in client-side applications where there is a greater chance that the token can be intercepted by a malicious user. For this reason we prevent direct API requests through our cross-origin resource sharing (CORS) policy.

Use the token refresh utility found here to refresh the user's JWT when it expires.

const request = require('request');

// input client_id, refresh_token, access_token
return request({
  uri: '',
  method: 'POST',
  json: {
    grant_type: 'refresh_token',
}, (error, {statusCode = 500, body = null}) => {
  // handle error and statusCode !== 2xx
  return console.log(body.access_token);

This will return a new JWT for the user.

Updated 9 months ago


Suggested Edits are limited on API Reference Pages

You can only suggest edits to Markdown body content, but not to the API spec.