- Sign a JWT client assertion with your ES256 private key.
- Exchange it for a short-lived access token.
- Call a metadata endpoint with the access token.
private_key.pem) next to the script. Replace <OAuthClientId> and <KID> with the values from your onboarding pack. See Request an access token for what each step does.
- TypeScript
- Python
Requires Node.js 18 or later for the global
fetch.npm install jsonwebtoken
npm install --save-dev typescript tsx @types/jsonwebtoken @types/node
npx tsx sample_request.ts
sample_request.ts
import { randomUUID } from 'node:crypto';
import { readFileSync } from 'node:fs';
import jwt from 'jsonwebtoken';
// ---------------------------------------------------------------------------
// Configuration — fill these in for your environment.
// ---------------------------------------------------------------------------
const OAUTH_CLIENT_ID = '<OAuthClientId>'; // Your OAuth Client Id (from your onboarding pack)
const KID = '<KID>'; // The Kid whose PRIVATE key you're using to sign below
const PRIVATE_KEY_PATH = './private_key.pem'; // Path to the PRIVATE key matching that Kid's public key
const GATEWAY_BASE_URL = 'https://gateway.creditbenchmark.com';
const TOKEN_URL = 'https://gateway.creditbenchmark.com/api/security/token';
const AUDIENCE = 'cb-gateway-m2m-blue';
// Any of the metadata endpoints below — change as needed.
const METADATA_ENDPOINT = '/beta/metadata/columns';
/** Builds and signs the RFC 7523 JWT bearer client assertion. */
function buildClientAssertion(): string {
const privateKeyPem = readFileSync(PRIVATE_KEY_PATH, 'utf8');
const now = Math.floor(Date.now() / 1000);
return jwt.sign(
{
iss: OAUTH_CLIENT_ID,
sub: OAUTH_CLIENT_ID,
aud: AUDIENCE,
jti: randomUUID(),
iat: now,
exp: now + 120,
},
privateKeyPem,
{ algorithm: 'ES256', keyid: KID }
);
}
/** Exchanges the signed client assertion for a short-lived access token. */
async function getAccessToken(): Promise<string> {
const clientAssertion = buildClientAssertion();
const body = new URLSearchParams({
grant_type: 'client_credentials',
client_assertion_type: 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
client_assertion: clientAssertion,
OAuthClientId: OAUTH_CLIENT_ID,
});
const response = await fetch(TOKEN_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body,
});
if (!response.ok) {
throw new Error(`Token request failed: ${response.status} ${await response.text()}`);
}
const data = (await response.json()) as { accessToken: string };
return data.accessToken;
}
/** Calls a metadata API using the access token. Swap 'endpoint' for any of
* the other metadata endpoints. */
async function callMetadataEndpoint(accessToken: string, endpoint: string = METADATA_ENDPOINT): Promise<unknown> {
const response = await fetch(`${GATEWAY_BASE_URL}${endpoint}`, {
headers: {
Authorization: `Bearer ${accessToken}`,
'Content-Type': 'application/json',
Accept: 'application/json',
},
});
if (!response.ok) {
throw new Error(`Metadata request failed: ${response.status} ${await response.text()}`);
}
return response.json();
}
(async () => {
const token = await getAccessToken();
console.log('Access token acquired.');
const data = await callMetadataEndpoint(token);
console.log(`Response from ${METADATA_ENDPOINT}:`);
console.log(data);
})().catch((err) => {
console.error(err);
process.exitCode = 1;
});
Requires Python 3.8 or later.
pip install "requests>=2.31.0" "PyJWT>=2.8.0" "cryptography>=41.0.0"
python sample_request.py
sample_request.py
import time
import uuid
import jwt # PyJWT
import requests
# ---------------------------------------------------------------------------
# Configuration — fill these in for your environment.
# ---------------------------------------------------------------------------
OAUTH_CLIENT_ID = "<OAuthClientId>" # Your OAuth Client Id (from your onboarding pack)
KID = "<KID>" # The Kid whose PRIVATE key you're using to sign below
PRIVATE_KEY_PATH = "private_key.pem" # Path to the PRIVATE key matching that Kid's public key
GATEWAY_BASE_URL = "https://gateway.creditbenchmark.com"
TOKEN_URL = "https://gateway.creditbenchmark.com/api/security/token"
AUDIENCE = "cb-gateway-m2m-blue"
# Any of the metadata endpoints below — change as needed.
METADATA_ENDPOINT = "/beta/metadata/columns"
def build_client_assertion() -> str:
"""Builds and signs the RFC 7523 JWT bearer client assertion."""
with open(PRIVATE_KEY_PATH, "r", encoding="utf-8") as f:
private_key_pem = f.read()
now = int(time.time())
payload = {
"iss": OAUTH_CLIENT_ID,
"sub": OAUTH_CLIENT_ID,
"aud": AUDIENCE,
"jti": str(uuid.uuid4()),
"iat": now,
"exp": now + 120,
}
headers = {"kid": KID}
return jwt.encode(payload, private_key_pem, algorithm="ES256", headers=headers)
def get_access_token() -> str:
"""Exchanges the signed client assertion for a short-lived access token."""
client_assertion = build_client_assertion()
response = requests.post(
TOKEN_URL,
data={
"grant_type": "client_credentials",
"client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
"client_assertion": client_assertion,
"OAuthClientId": OAUTH_CLIENT_ID,
},
headers={"Content-Type": "application/x-www-form-urlencoded"},
timeout=30,
)
response.raise_for_status()
return response.json()["accessToken"]
def call_metadata_endpoint(access_token: str, endpoint: str = METADATA_ENDPOINT) -> dict:
"""Calls a metadata API using the access token. Swap 'endpoint' for any
of the other metadata endpoints."""
response = requests.get(
f"{GATEWAY_BASE_URL}{endpoint}",
headers={
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/json",
"Accept": "application/json",
},
timeout=30,
)
response.raise_for_status()
return response.json()
if __name__ == "__main__":
token = get_access_token()
print("Access token acquired.")
data = call_metadata_endpoint(token)
print(f"Response from {METADATA_ENDPOINT}:")
print(data)
Metadata endpoints
SetMETADATA_ENDPOINT to any of these. All are GET requests.
| Endpoint | Returns |
|---|---|
/beta/metadata/columns | Available input columns with type, scopeable, facetable, and entitlement |
/beta/metadata/available-dates | Latest effective date and latest finalised effective date |
/beta/metadata/geography-schema | Region group, region, and country hierarchy |
/beta/metadata/rating-scales | Supported rating scales and their grade mappings |
Never share your private key with anyone, including Credit Benchmark. Generate a new client assertion for every token request, and if a private key is ever compromised, follow key rotation.

