CyberGuard
by Inside Technologies Srl

Authentication

The API uses OAuth 2.0 client credentials, the same standard used by Microsoft Graph for app-only access.

Two steps:

  1. Exchange the Client ID and Client secret for an access token.
  2. Send the token in every request, in the Authorization header.

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.