Sample code for 30+ languages & platforms
React Native Requires Chilkat v11.7.0+

Enthuse API: DPoP Access Token with a Client Assertion (private_key_jwt)

See more OAuth2 Examples

Demonstrates how to get a DPoP-bound access token from the Enthuse API with the OAuth2 client credentials grant, and call the API. Enthuse authenticates the client with a client assertion (private_key_jwt): a short-lived JWT signed with the private key of the client, which must be created anew for each token request. The access token is bound to a DPoP key (RFC 9449), so each request also needs a new DPoP proof.

Chilkat does all of this automatically: SetClientAssertionKey provides the key for the client assertion, SetDPoPKey provides the DPoP key, and the AuthToken property provides the client credentials. Chilkat requests the access token when it is needed, sends the Authorization: DPoP and DPoP headers with each API request, and requests a new token when the current one is about to expire.

Note: Requires Chilkat v11.7.0 or later.

Chilkat React Native Downloads

React Native
import { Http, HttpResponse, JsonObject, PrivateKey, Rsa, StringBuilder } from '@chilkat/react-native'

async function chilkatExample() {
  // This example requires Chilkat v11.7.0 or later.

  // It gets an access token from Enthuse with the OAuth2 client credentials grant, using a
  // client assertion (private_key_jwt) for client authentication and DPoP for the token binding,
  // and then calls the Enthuse API.  Chilkat creates the client assertion and the DPoP proofs.

  // Load the client private key.  Enthuse Cloud gives it to you as a JWK file when you create
  // the client (Integration -> API -> Create Client).
  const sbJwk = new StringBuilder();
  try {
    sbJwk.loadFile('qa_data/enthuse/client_key.jwk', 'utf-8');
  } catch {
    console.log(sbJwk.lastErrorText);
    return;
  }

  const clientKey = new PrivateKey();
  try {
    clientKey.loadJwk(sbJwk.getAsString());
  } catch {
    console.log(clientKey.lastErrorText);
    return;
  }

  // Get the key ID (kid) from the JWK.
  const jwk = new JsonObject();
  try {
    jwk.load(sbJwk.getAsString());
  } catch {
    console.log(jwk.lastErrorText);
    return;
  }

  const kid = jwk.stringOf('kid');

  const http = new Http();

  // Enthuse production is behind Cloudflare, which rejects some default HTTP user agents.
  // Send a User-Agent that identifies your integration.  Chilkat sends it with the token
  // request and with every API call.
  http.userAgent = 'ExampleCharity-CRM/1.0';

  // Provide the client key for the client assertion.  For each token request, Chilkat creates
  // a new client_assertion JWT signed with this key, with the claims iss and sub (the client_id),
  // aud (the token_endpoint), iat, exp (5 minutes after iat) and a unique jti, and the kid
  // in its header.  It is sent with client_assertion_type set to
  // urn:ietf:params:oauth:client-assertion-type:jwt-bearer.
  try {
    http.setClientAssertionKey(clientKey, kid);
  } catch {
    console.log(http.lastErrorText);
    return;
  }

  // Provide the DPoP key.  It can be the client key or a separate key, but the same DPoP key
  // must be used for the token request and for the API calls.  This example generates a
  // separate RSA key (the DPoP proofs are then signed with RS256).
  const rsa = new Rsa();
  const dpopKey = new PrivateKey();
  try {
    rsa.genKey(2048, dpopKey);
  } catch {
    console.log(rsa.lastErrorText);
    return;
  }

  try {
    http.setDPoPKey(dpopKey);
  } catch {
    console.log(http.lastErrorText);
    return;
  }

  // Provide the details for the client credentials token request.  Every member except
  // token_endpoint is sent as a form field.  Use the client_id and org_id issued by
  // the Enthuse environment you call.  For the development environment, use
  // https://identity.enthuse-test.com/oidc/token and https://api.enthuse-test.com instead.
  const json = new JsonObject();
  json.updateString('client_id', 'ab12cd34-ef56-7890-ab12-cd34ef567890');
  json.updateString('org_id', '123');
  json.updateString('scope', 'org.read org.pii');
  json.updateString('resource', 'https://api.enthuse.cloud');
  json.updateString('token_endpoint', 'https://identity.enthuse.cloud/oidc/token');
  http.authToken = json.emit();

  http.accept = 'application/json';

  // Call the API.  There is no access token yet, so Chilkat first sends the token request
  // to the token_endpoint, with the client assertion and a DPoP proof for POST to the token
  // endpoint.  Chilkat then sends the API request with these headers:

  // Authorization: DPoP <access_token>
  // DPoP: <a new DPoP proof for POST https://api.enthuse.cloud/v3/payments, with the ath claim>

  // The proof's htu claim is the URL without its query string.
  // Enthuse access tokens last 600 seconds.  Chilkat reuses the token for later requests made
  // with the same Http object, with a new DPoP proof for each request, and gets a new token
  // (with a new client assertion) when the token is about to expire.

  const resp = new HttpResponse();
  try {
    await http.httpNoBodyAsync('POST', 'https://api.enthuse.cloud/v3/payments?since=2026-08-01T00:00:00Z', resp);
  } catch {
    console.log(http.lastErrorText);
    return;
  }

  console.log(`Response status code = ${resp.statusCode}`);

  // The data endpoints return NDJSON: one JSON object per line, then a final "_meta" line.
  console.log(resp.bodyStr);
}