Overview
The QBench API v2 uses OAuth 2.0 standards with JWT-based authentication. To integrate your application with QBench, you will:
- Create an API client in QBench to obtain a Client ID and Client Secret.
- Use the Client ID and Client Secret to generate a signed JSON Web Token (JWT).
- Exchange the JWT for an access token.
- Use the access token to make authenticated API calls.
API Documentation
Full endpoint documentation for the v2 API is available in two locations:
- Within QBench: Navigate to Configuration > Application > Developer > Settings, select your API Client, and click the Docs tab. This opens an interactive Swagger UI at {QBENCH_URL}/qbench/api/v2/docs/openapi/{API_CLIENT_ID} where you can browse endpoints and make live requests.
- External: QBench API v2 Documentation
Creating an API Client
Before you can authenticate, you need to create an API client in QBench.
- Navigate to Configuration > Application > Developer > Settings.
- In the API Clients section, click +New Client.
- Fill in the following fields:
- Name: A descriptive name for your integration (e.g., "LIMS Integration - Production").
- Type: Select Server-Side Web Application.
- CORS Origin: Add your application's origin URL if making browser-based requests. Leave blank for server-to-server integrations.
- Click Save.
- The system will generate and display your Client ID and Client Secret.
After saving, two additional tabs become available:
- Scopes: Configure which API v2 endpoints this client can access.
- Docs: Opens the interactive Swagger UI for this client, pre-populated with a valid JWT assertion for testing.
Important: Store your Client ID and Client Secret securely. The Client Secret is used to sign JWTs and must never be exposed in client-side code or committed to version control.
Authentication — Creating a JWT
A JSON Web Token (JWT) is composed of three Base64url-encoded parts separated by periods (.):
{Base64url encoded header}.{Base64url encoded claim set}.{Base64url encoded signature}JWT Header
The header is always the same:
{"alg": "HS256", "typ": "JWT"}
Base64url encoded: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9JWT Claim Set
The claim set contains the following required fields:
| Field | Description |
| sub | Your Client ID |
| iat | Issued at time — seconds since January 1, 1970 00:00:00 UTC |
| exp | Expiration time — seconds since January 1, 1970 00:00:00 UTC |
Constraints:
- exp must be at least 5 minutes and at most 1 hour after iat.
- iat must be within 5 minutes of the current server time (UTC).
Example claim set:
{
"sub": "your_client_id",
"iat": 1491596166,
"exp": 1491599766
}JWT Signature
Sign the concatenation of the Base64url-encoded header and claim set using HMAC-SHA256 with your Client Secret:
HMAC-SHA256(
key = client_secret,
message = "{Base64url encoded header}.{Base64url encoded claim set}"
)The signature is then Base64url-encoded and appended to produce the final JWT:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ5b3VyX2NsaWVudF9pZCIsImlhdCI6MTQ5MTU5NjE2NiwiZXhwIjoxNDkxNTk5NzY2fQ.{signature}Code Examples
Python
import jwt
import time
client_id = "your_client_id"
client_secret = "your_client_secret"
now = int(time.time())
payload = {
"sub": client_id,
"iat": now,
"exp": now + 3600 # 1 hour from now
}
token = jwt.encode(payload, client_secret, algorithm="HS256")
print(token)Requires the PyJWT library: pip install PyJWT
JavaScript
const jwt = require("jsonwebtoken");
const clientId = "your_client_id";
const clientSecret = "your_client_secret";
const now = Math.floor(Date.now() / 1000);
const payload = {
sub: clientId,
iat: now,
exp: now + 3600, // 1 hour from now
};
const token = jwt.sign(payload, clientSecret, { algorithm: "HS256" });
console.log(token);Requires the jsonwebtoken library: npm install jsonwebtoken
Requesting an Access Token
Exchange your signed JWT for an access token.
Endpoint:
POST {QBENCH_URL}/qbench/api/v2/auth/tokenHeaders:
Content-Type: application/x-www-form-urlencodedParameters:
| Parameter | Value |
| grant_type | urn:ietf:params:oauth:grant-type:jwt-bearer |
| assertion | Your signed JWT |
Response:
{
"access_token": "63ff42c5-49e6-42e2-bc3f-04fbfc22bbcb",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}Code Examples
cURL
curl -X POST https://{QBENCH_URL}/qbench/api/v2/auth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion={JWT}"Python
import requests
url = "https://{QBENCH_URL}/qbench/api/v2/auth/token"
data = {
"grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",
"assertion": token # JWT from previous step
}
response = requests.post(url, data=data)
result = response.json()
access_token = result["access_token"]
refresh_token = result["refresh_token"]
print(f"Access Token: {access_token}")
print(f"Refresh Token: {refresh_token}")JavaScript
const url = "https://{QBENCH_URL}/qbench/api/v2/auth/token";
const params = new URLSearchParams({
grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
assertion: token, // JWT from previous step
});
const response = await fetch(url, {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: params,
});
const result = await response.json();
console.log("Access Token:", result.access_token);
console.log("Refresh Token:", result.refresh_token);Refreshing an Access Token
When your access token expires, you can use the refresh token to obtain a new one without re-creating a JWT.
Endpoint:
POST {QBENCH_URL}/qbench/api/v2/auth/token/refreshHeaders:
Content-Type: application/x-www-form-urlencodedParameters:
| Parameter | Value |
| refresh_token_id | The refresh_token value from the original token response |
The refresh token JWT is also sent via a jid cookie, which is set automatically by the browser from the original token response.
Response:
{
"access_token": "new-access-token-uuid",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "new-refresh-token-uuid"
}Key details:
- Refresh tokens expire after 7 days.
- Each refresh token can only be used once. After use, it is invalidated and a new refresh token is returned. Always store the latest refresh token.
- If a previously used refresh token is reused, it will be permanently invalidated for security.
Code Examples
cURL
curl -X POST https://{QBENCH_URL}/qbench/api/v2/auth/token/refresh \
-H "Content-Type: application/x-www-form-urlencoded" \
-b "jid={REFRESH_TOKEN_JWT}" \
-d "refresh_token_id={REFRESH_TOKEN_ID}"Python
import requests
url = "https://{QBENCH_URL}/qbench/api/v2/auth/token/refresh"
data = {
"refresh_token_id": refresh_token # from the original token response
}
cookies = {
"jid": refresh_token_jwt # the refresh token JWT cookie
}
response = requests.post(url, data=data, cookies=cookies)
result = response.json()
access_token = result["access_token"]
refresh_token = result["refresh_token"]
print(f"New Access Token: {access_token}")
print(f"New Refresh Token: {refresh_token}")JavaScript
const url = "https://{QBENCH_URL}/qbench/api/v2/auth/token/refresh";
const params = new URLSearchParams({
refresh_token_id: refreshToken, // from the original token response
});
const response = await fetch(url, {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: params,
credentials: "include", // sends the jid cookie automatically
});
const result = await response.json();
console.log("New Access Token:", result.access_token);
console.log("New Refresh Token:", result.refresh_token);
Making API Calls
Once you have an access token, include it in the Authorization header of every request.
Authorization: Bearer {ACCESS_TOKEN}All date/time values sent and received via the QBench API v2 are in UTC.
All v2 endpoints follow the base URL pattern:
{QBENCH_URL}/qbench/api/v2/{resource}For a complete list of available endpoints, parameters, and response schemas, refer to the Swagger documentation:
- Within QBench: Configuration > Application > Developer > Settings > select your API Client > Docs tab
- External: QBench API v2 Documentation
Code Examples
cURL
curl https://{QBENCH_URL}/qbench/api/v2/orders \
-H "Authorization: Bearer {ACCESS_TOKEN}"Python
import requests
url = "https://{QBENCH_URL}/qbench/api/v2/orders"
headers = {
"Authorization": f"Bearer {access_token}"
}
response = requests.get(url, headers=headers)
print(response.json())JavaScript
const url = "https://{QBENCH_URL}/qbench/api/v2/orders";
const response = await fetch(url, {
headers: {
Authorization: `Bearer ${accessToken}`,
},
});
const data = await response.json();
console.log(data);
Putting It All Together
Complete end-to-end examples that create a JWT, obtain an access token, and make an API call.
Python
import jwt
import requests
import time
# Configuration
QBENCH_URL = "https://{QBENCH_URL}"
CLIENT_ID = "your_client_id"
CLIENT_SECRET = "your_client_secret"
# 1. Create JWT
now = int(time.time())
payload = {"sub": CLIENT_ID, "iat": now, "exp": now + 3600}
token = jwt.encode(payload, CLIENT_SECRET, algorithm="HS256")
# 2. Exchange JWT for access token
auth_response = requests.post(
f"{QBENCH_URL}/qbench/api/v2/auth/token",
data={
"grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",
"assertion": token,
},
)
auth_result = auth_response.json()
access_token = auth_result["access_token"]
# 3. Make an API call
response = requests.get(
f"{QBENCH_URL}/qbench/api/v2/orders",
headers={"Authorization": f"Bearer {access_token}"},
)
print(response.json())JavaScript
const jwt = require("jsonwebtoken");
// Configuration
const QBENCH_URL = "https://{QBENCH_URL}";
const CLIENT_ID = "your_client_id";
const CLIENT_SECRET = "your_client_secret";
async function main() {
// 1. Create JWT
const now = Math.floor(Date.now() / 1000);
const token = jwt.sign(
{ sub: CLIENT_ID, iat: now, exp: now + 3600 },
CLIENT_SECRET,
{ algorithm: "HS256" }
);
// 2. Exchange JWT for access token
const authResponse = await fetch(
`${QBENCH_URL}/qbench/api/v2/auth/token`,
{
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
assertion: token,
}),
}
);
const authResult = await authResponse.json();
const accessToken = authResult.access_token;
// 3. Make an API call
const response = await fetch(`${QBENCH_URL}/qbench/api/v2/orders`, {
headers: { Authorization: `Bearer ${accessToken}` },
});
const data = await response.json();
console.log(data);
}
main();cURL
# 1. Create JWT (using Python as a helper — cURL cannot generate JWTs natively)
JWT=$(python3 -c "
import jwt, time
now = int(time.time())
print(jwt.encode({'sub': 'your_client_id', 'iat': now, 'exp': now + 3600}, 'your_client_secret', algorithm='HS256'))
")
# 2. Exchange JWT for access token
ACCESS_TOKEN=$(curl -s -X POST https://{QBENCH_URL}/qbench/api/v2/auth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=${JWT}" \
| python3 -c "import sys, json; print(json.load(sys.stdin)['access_token'])")
# 3. Make an API call
curl https://{QBENCH_URL}/qbench/api/v2/orders \
-H "Authorization: Bearer ${ACCESS_TOKEN}"
Token Lifecycle Summary
| Token | Lifetime | How to Obtain | How to Renew |
| Access Token | 1 hour | POST /qbench/api/v2/auth/token with JWT | Request a new one, or use refresh token |
| Refresh Token | 7 days | Returned with access token response | Automatically rotated on each use |
| JWT | Up to 1 hour (5 min minimum) | Generated client-side with Client ID + Secret | Generate a new one |
Comments
0 comments
Please sign in to leave a comment.