Authentication
The API uses OAuth 2.0 client credentials, the same standard used by Microsoft Graph for app-only access.
Two steps:
- Exchange the Client ID and Client secret for an access token.
- Send the token in every request, in the
Authorizationheader.
The token is valid for 60 minutes. Reuse it until it expires, then request a new one.
Get a token
POST https://inventory-api.cyberguard.srl/connect/token
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials&client_id=<Client ID>&client_secret=<Client secret>
Optional: add scope=devices.read compliance.read to request only some of the client's scopes.
Response:
{
"access_token": "eyJhbGciOi...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "devices.read compliance.read",
"api_base_url": "https://inventory-api.cyberguard.srl"
}
The client credentials can also be sent as HTTP Basic authentication (Authorization: Basic base64(client_id:client_secret)).
Use the API address shown in the API page of the portal. The example above is the address for customers whose data is hosted in Italy.
Call the API
GET https://inventory-api.cyberguard.srl/v1/devices
Authorization: Bearer <access_token>
Examples
PowerShell
$base = "https://inventory-api.cyberguard.srl"
$token = Invoke-RestMethod -Method Post -Uri "$base/connect/token" -Body @{
grant_type = "client_credentials"
client_id = "<Client ID>"
client_secret = "<Client secret>"
}
$headers = @{ Authorization = "Bearer $($token.access_token)" }
# All devices, page by page
$devices = @()
$cursor = $null
do {
$uri = "$base/v1/devices?pageSize=500" + $(if ($cursor) { "&cursor=$cursor" })
$page = Invoke-RestMethod -Uri $uri -Headers $headers
$devices += $page.data
$cursor = $page.nextCursor
} while ($cursor)
$devices | Select-Object deviceName, serialNumber, complianceState | Format-Table
Python
import requests
base = "https://inventory-api.cyberguard.srl"
token = requests.post(f"{base}/connect/token", data={
"grant_type": "client_credentials",
"client_id": "<Client ID>",
"client_secret": "<Client secret>",
}).json()["access_token"]
headers = {"Authorization": f"Bearer {token}"}
devices, cursor = [], None
while True:
params = {"pageSize": 500}
if cursor:
params["cursor"] = cursor
page = requests.get(f"{base}/v1/devices", headers=headers, params=params).json()
devices.extend(page["data"])
cursor = page["nextCursor"]
if not cursor:
break
print(len(devices), "devices")
Token errors
| Status | error |
Meaning |
|---|---|---|
400 |
unsupported_grant_type |
Use grant_type=client_credentials |
400 |
invalid_scope |
A requested scope is not granted to the client or not included in your license |
400 |
unauthorized_client |
The API add-on is not active or has expired |
401 |
invalid_client |
Wrong Client ID or secret, or the client or secret has been revoked or has expired |
429 |
slow_down |
Too many tokens requested (max 20 per hour per client), or too many failed attempts from the same IP address |
Failed attempts for an existing client are recorded in your Audit log with the IP address.
Keep the secret safe
- Store the secret in a secrets vault or as a protected parameter, not in plain text in scripts or shared files.
- Create a separate client for each system. You can revoke one without affecting the others.
- Renew secrets before they expire (12 months) and revoke the previous one when the system uses the new one.