Developer Guide - Authenticating To The OrderCentral API With Salesforce JWT Bearer Flow

Prev Next

This guide explains how to authenticate against the OrderCentral API using Salesforce’s JWT Bearer OAuth Flow through a configured External Client App.
This flow is designed for secure server-to-server integrations with no user interaction required.

What You Receive from the OrderCentral Admin

Before you begin, the Salesforce admin must provide you with:

  1. Client ID (from the External Client App)
  2. Salesforce OAuth Domain, such as:
    • https://login.salesforce.com (production)
    • https://test.salesforce.com (sandbox)
    • or a My Domain URL (e.g. https://mydomain.my.salesforce.com)
  3. Salesforce Username that your integration should impersonate
  4. OAuth scopes that are allowed (at minimum: api)
  5. The public certificate (optional)
    You must have:
  • The private key matching the certificate the admin uploaded. This is used to sign JWTs with RS256.

Flow Overview

Your system will:

  1. Create a JWT containing required Salesforce claims.
  2. Sign the JWT using RS256 and the private key.
  3. POST the signed JWT to Salesforce at /services/oauth2/token.
  4. Receive an access token and instance URL.
  5. Call the OrderCentral API with the access token.
  6. Repeat when the token expires (no refresh token is used in this flow).

Constructing the JWT

A valid JWT has a header, payload, and signature.

Header

{
  "alg": "RS256"
}

Payload Claims

The JWT payload must contain:

Claim Description
iss Client ID of the External Client App
sub Salesforce username to impersonate
aud Salesforce OAuth domain (the login host)
exp Expiration time (Unix timestamp). Usually now + 3 to 5 minutes

Example:

{
  "iss": "3MVG9...ClientId",
  "sub": "[email protected]",
  "aud": "https://login.salesforce.com",
  "exp": 1733839800
}

Signing the JWT

Sign the JWT using RS256 with your private key.
The resulting string must be formatted as:

{Base64UrlHeader}.{Base64UrlPayload}.{Base64UrlSignature}

Requesting an Access Token from Salesforce from Salesforce

Endpoint

POST {OAUTH_DOMAIN}/services/oauth2/token

Where {OAUTH_DOMAIN} is the domain the admin provided.

Request Body

Send the following as URL-encoded form data:

grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer
assertion={YOUR_SIGNED_JWT}

Example Curl Request

curl -X POST "https://login.salesforce.com/services/oauth2/token" \
  -d "grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer" \
  -d "assertion=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."

Example Response

{
  "access_token": "00Dxx0000001gERT!...",
  "scope": "api",
  "instance_url": "https://mydomain.my.salesforce.com",
  "id": "https://login.salesforce.com/id/00Dxx0000001gERT/005xx000001Sv6V",
  "token_type": "Bearer",
  "issued_at": "1733837468925",
  "signature": "wxyz..."
}

Key Values You Need

  • access_token: used for API calls
  • instance_url: base URL for OrderCentral API endpoints

Calling the OrderCentral API

Use the access_token and instance_url from the token response.
All calls must include:

Authorization: Bearer {access_token}
Content-Type: application/json

Example

curl -X GET \
  "{instance_url}/services/apexrest/ordercentral/v1/orders" \
  -H "Authorization: Bearer 00Dxx0000..." \
  -H "Content-Type: application/json"

Replace /ordercentral/v1/orders with the correct path for your project.

Token Expiration Handling

The JWT flow does not return a refresh token. When an access token expires:

  1. Generate a new JWT with a fresh exp claim.
  2. Sign it again using RS256.
  3. POST it to Salesforce using the same endpoint.
  4. Receive a new access token.
    This process can be repeated indefinitely.

Example Implementation (Node.js) (Node.js)

import fs from "fs";
import * as jose from "jose";
const clientId = process.env.SF_CLIENT_ID;
const username = process.env.SF_USERNAME;
const authDomain = process.env.SF_AUTH_DOMAIN; // e.g. https://login.salesforce.com
const privateKeyPem = fs.readFileSync("./private.key", "utf8");
async function getAccessToken() {
  const now = Math.floor(Date.now() / 1000);
  const payload = {
    iss: clientId,
    sub: username,
    aud: authDomain,
    exp: now + 3 * 60
  };
  const privateKey = await jose.importPKCS8(privateKeyPem, "RS256");
  const jwt = await new jose.SignJWT(payload)
    .setProtectedHeader({ alg: "RS256" })
    .sign(privateKey);
  const params = new URLSearchParams();
  params.append("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer");
  params.append("assertion", jwt);
  const response = await fetch(`${authDomain}/services/oauth2/token`, {
    method: "POST",
    headers: { "Content-Type": "application/x-www-form-urlencoded" },
    body: params.toString()
  });
  if (!response.ok) {
    throw new Error(await response.text());
  }
  const data = await response.json();
  return {
    accessToken: data.access_token,
    instanceUrl: data.instance_url
  };
}

Common Errors

  • invalid_grant: User not approved, wrong sub, wrong aud, or expired exp.
  • unsupported_grant_type: Ensure the grant type string is correct.
  • invalid_client_id: Using the wrong Client ID or environment.

Summary

To authenticate using the External Client App via JWT Bearer:

  1. Build a JWT containing iss, sub, aud, and exp.
  2. Sign it with RS256 using your private key.
  3. Exchange it for an access token using Salesforce's /token endpoint.
  4. Use the token to call OrderCentral REST endpoints.
  5. Regenerate tokens as needed.
    You now have everything required to integrate securely with the OrderCentral API.