Authentication¶
This API uses a Client Credentials style system-to-system authentication model.
It is not a full standalone OAuth Authorization Server. It provides a standards-aligned token endpoint and Bearer JWT protection for protected API routes.
First-version model¶
| Decision | Value |
|---|---|
| Flow | Client Credentials |
| Clients | Single standard integration client |
| Credential source | Environment variables (.env) |
| Token request auth | HTTP Basic |
| Access token | JWT (HS256) |
| Default lifetime | 60 minutes (expires_in=3600) |
| Refresh token | Not supported |
| Scopes | Not supported |
| MongoDB client registry | Not used |
Configuration¶
| Variable | Default | Notes |
|---|---|---|
AUTH_ENABLED |
false |
Enables token endpoint and Bearer protection |
AUTH_CLIENT_ID |
empty | Required when enabled |
AUTH_CLIENT_SECRET |
empty | Required when enabled, minimum 32 characters |
AUTH_JWT_SECRET |
empty | Required when enabled, minimum 32 bytes, must differ from client secret |
AUTH_ISSUER |
iqv-integration-api |
JWT iss |
AUTH_AUDIENCE |
iqv-integration-api |
JWT aud |
AUTH_ACCESS_TOKEN_TTL |
60m |
Positive, maximum 24h |
AUTH_TOKEN_MAX_BODY_BYTES |
16384 |
Token endpoint body limit |
AUTH_ENABLED=false¶
- Token endpoint is not registered (
404) POST /api/v1/inbound/work-ordersremains open without Bearer tokens- Suitable for local development
AUTH_ENABLED=true¶
Example:
env
AUTH_ENABLED=true
AUTH_CLIENT_ID=iqv-standard-integration
AUTH_CLIENT_SECRET=
AUTH_JWT_SECRET=
AUTH_ISSUER=iqv-integration-api
AUTH_AUDIENCE=iqv-integration-api
AUTH_ACCESS_TOKEN_TTL=60m
Generate secrets locally (do not commit them):
```powershell
48-character random secret example (do not commit the result)¶
$alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' -join (1..48 | ForEach-Object { $alphabet[(Get-Random -Maximum $alphabet.Length)] }) ```
Prefer a cryptographically secure generator in production secret management.
Token endpoint¶
text
POST {PUBLIC_BASE_URL}/api/v1/auth/token
Request¶
Headers:
http
Authorization: Basic BASE64(client_id:client_secret)
Content-Type: application/x-www-form-urlencoded
Accept: application/json
Body:
text
grant_type=client_credentials
Rules:
- Credentials must come only from the Basic Authorization header
- Do not send
client_id/client_secretin the body or query string - JSON request bodies are rejected (
415) - Token endpoint responses are JSON only
Success response¶
json
{
"success": true,
"request_id": "uuid",
"data": {
"access_token": "jwt-token",
"token_type": "Bearer",
"expires_in": 3600
},
"error": null
}
Headers include Cache-Control: no-store and Pragma: no-cache.
Using the access token¶
Protected endpoints require:
http
Authorization: Bearer <access_token>
Example work-order call:
http
POST {PUBLIC_BASE_URL}/api/v1/inbound/work-orders
Authorization: Bearer <access_token>
Content-Type: application/json
Accept: application/json
XML requests use the same Authorization header:
http
POST {PUBLIC_BASE_URL}/api/v1/inbound/work-orders
Authorization: Bearer <access_token>
Content-Type: application/xml
Accept: application/xml
Client runtime guidance (ERP / cron)¶
- Obtain a token with client credentials.
- Store the token in secure memory/cache.
- Reuse the token for POST (and future GET) calls while it remains valid.
- Do not request a new token on every cron run.
- Renew when the token is missing, expired, or will expire within 5 minutes.
- Do not use refresh tokens.
- If the API returns
401, obtain one new token and retry the request once.
Public vs protected routes¶
Public:
GET /GET /health/liveGET /health/readyGET /health/details(existing enablement rules unchanged)POST /api/v1/auth/token(only when auth is enabled)
Protected when AUTH_ENABLED=true:
POST /api/v1/inbound/work-orders
Transport security¶
- Production must use HTTPS / TLS.
- Local development may use HTTP on trusted networks.
- Never send client secrets or access tokens over untrusted cleartext channels.
Error codes¶
| Code | HTTP | Meaning |
|---|---|---|
INVALID_REQUEST |
400 | Missing grant_type or malformed token request |
UNSUPPORTED_GRANT_TYPE |
400 | grant_type is not client_credentials |
INVALID_CLIENT |
401 | Basic client authentication failed |
AUTHENTICATION_REQUIRED |
401 | Bearer token missing |
INVALID_TOKEN |
401 | Bearer token invalid or expired |
NOT_ACCEPTABLE |
406 | Unsupported Accept on token endpoint |
PAYLOAD_TOO_LARGE |
413 | Token body exceeds limit |
UNSUPPORTED_MEDIA_TYPE |
415 | Non-form token request Content-Type |
INTERNAL_ERROR |
500 | Unexpected failure |
Postman¶
- Create a POST request to
{PUBLIC_BASE_URL}/api/v1/auth/token. - Authorization tab: Type Basic Auth, username = client id, password = client secret.
- Body:
x-www-form-urlencoded, keygrant_type=client_credentials. - Headers:
Accept: application/json. - Copy
data.access_token. - On work-order requests, set Authorization type Bearer Token.
PowerShell example¶
```powershell $baseUrl = $env:PUBLIC_BASE_URL
Token request via curl.exe to avoid embedding secrets in local scripts¶
$tokenJson = curl.exe -sS -X POST "$baseUrl/api/v1/auth/token" -u "$($env:AUTH_CLIENT_ID):$($env:AUTH_CLIENT_SECRET)"
-H "Content-Type: application/x-www-form-urlencoded" -H "Accept: application/json"
-d "grant_type=client_credentials"
$tokenResponse = $tokenJson | ConvertFrom-Json $accessToken = $tokenResponse.data.access_token
curl.exe -sS -X POST "$baseUrl/api/v1/inbound/work-orders" -H "Authorization: Bearer $accessToken"
-H "Content-Type: application/json" -H "Accept: application/json"
--data-binary "@work-order.json"
```
curl example¶
```bash BASE_URL="${PUBLIC_BASE_URL}"
curl -sS -X POST "${BASE_URL}/api/v1/auth/token" \ -u "${AUTH_CLIENT_ID}:${AUTH_CLIENT_SECRET}" \ -H "Content-Type: application/x-www-form-urlencoded" \ -H "Accept: application/json" \ -d "grant_type=client_credentials"
curl -sS -X POST "${BASE_URL}/api/v1/inbound/work-orders" \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ -H "Content-Type: application/json" \ -H "Accept: application/json" \ --data-binary @work-order.json ```
Production hardening follow-ups¶
Not implemented in this branch, but recommended later:
- Token endpoint rate limiting
- Secret rotation procedures
- Optional multi-client registry (if required by a future release)