Skip to content
Avanet
Sign in

Manage Sophos Central API credentials securely

Sophos Fusion (formerly Sophos Central) can be automated through APIs and connected to SIEM, RMM, reporting, or insurance platforms. These integrations should use dedicated API Credentials, consisting of a Client ID and Client Secret, rather than personal administrator accounts.

These credentials are machine identities. Anyone who has the secret can perform every API action permitted by the assigned service principal role. A secret must therefore be treated like a privileged password and must never appear in scripts, tickets, emails, or Git repositories.

Distinguish API Credentials from Integration Credential Manager

Under Global Settings > Access Control, Sophos Fusion provides two areas with similar names:

AreaPurpose
API CredentialsMachine identity that an application uses to call the Sophos Fusion APIs
Integration Credential ManagerCredentials for third-party products that Sophos uses for integrations such as Data Ingestion or Response Actions

Create API Credentials for an in-house script, SIEM query, or API client. Credentials for a third-party product that Sophos Fusion itself needs to use belong in Integration Credential Manager.

Not every automation task requires general API credentials: synchronize users and groups through a directory service, and deploy software through an installer script executed locally on each device. Create an API identity for AD Sync only when the intended synchronization workflow calls for it, and assign only Service Principal Directory Sync.

Prerequisites and ownership

Only a Super Admin can create and manage API credentials. The application authenticates with its own Client ID and Client Secret, not with the personal administrator account.

Before creating it, document the purpose, owner, target system, required role, expiration date, and emergency contact. Use a separate credential for each application and environment. Sharing one secret among a backup script, SIEM, and external service provider prevents targeted revocation and makes root-cause analysis difficult.

Choose the appropriate service principal role

Sophos provides several roles:

  • Service Principal Read-Only can read tenant data, but cannot modify it or run Live Discover queries.
  • Service Principal Management can query, create, modify, and delete users and user groups; query and act on alerts; query endpoints and trigger actions such as scans; and view or modify global Endpoint Protection settings. It also manages administrators, roles, and security policies, but has no Live Discover query access.
  • Service Principal Forensics creates, views, runs, and deletes Live Discover queries.
  • Service Principal Directory Sync is exclusively for Active Directory synchronization and cannot perform other API tasks.
  • Service Principal Firewall restricts the identity to firewall management and prevents Central API tasks outside that scope.
  • Service Principal Audit Log gives external applications, SIEM tools, and integration scripts read-only query access to retrieve audit log events.
  • Service Principal Super Admin has broad read, write, delete, and query permissions.

Always start with the narrowest role. A reporting or cyber-insurance integration receives Read-Only. AD Sync receives its dedicated role. Use Super Admin only when documented API endpoints genuinely require broad write permissions and no narrower role works.

Create a credential

Sign in at fusion.sophos.com, then open Global Settings > Access Control > API Credentials. The terms of use must be accepted on first access.

  1. Open Add Credential.
  2. Enter a unique name and a description that identifies the application, environment, and owner.
  3. Select the minimum required service principal role.
  4. Create the credential and immediately record the Client ID and Client Secret.
  5. Store the secret in an enterprise secret store and clear any temporary clipboard or working copy.

The Client Secret is displayed only once and cannot be revealed later. If it is lost, do not attempt to recover the existing secret. Create a new credential and delete the old one after a successful cutover.

API contract: token, identity, and data region

The following workflow describes the regional Sophos Central REST product APIs: the global identity host issues the OAuth token; the global whoami host identifies the credential. For REST product contracts with regional routing, tenant product requests then go to the host returned for that tenant. The following HTTPS targets must be reachable from the administration workstation or integration system for this purpose:

  • POST https://id.sophos.com/api/v2/oauth2/token for OAuth2;
  • GET https://api.central.sophos.com/whoami/v1 for identity and host discovery;
  • GET https://api.central.sophos.com/partner/v1/tenants for partner credentials;
  • GET https://api.central.sophos.com/organization/v1/tenants for Enterprise credentials;
  • the HTTPS host returned as apiHosts.dataRegion or the tenant’s apiHost for product APIs.

Do not guess a regional URL or copy it from a static table. For this REST workflow, accept only the complete HTTPS host returned, then append product paths. The host validation in the script below applies to this contract, not universally to every Sophos API.

The Search GraphQL API has its own target contract: JSON POST to https://api.taegis.sophos.com/graphql with a bearer token, X-Tenant-ID and X-GraphQL-Schema: default. Do not use the regional REST host for it or globally replace apiHosts.dataRegion. Token acquisition and tenant mapping remain necessary; clarify the required permissions and entitlements separately for the specific operation. The general role descriptions above do not establish a minimum Search GraphQL role. The runbook for historical Search QL queries covers the complete search workflow. The hostname alone does not establish a data-residency guarantee.

Request an access token securely

Read the secret without displaying it and send URL-encoded form data over standard input so it appears in neither shell history nor expanded process arguments:

read -r -p "Client ID: " SOPHOS_CLIENT_ID
read -r -s -p "Client Secret: " SOPHOS_CLIENT_SECRET
printf '\n'

TOKEN_RESPONSE=$(
  printf 'grant_type=client_credentials&client_id=%s&client_secret=%s&scope=token' \
    "$(printf '%s' "$SOPHOS_CLIENT_ID" | jq -sRr '@uri')" \
    "$(printf '%s' "$SOPHOS_CLIENT_SECRET" | jq -sRr '@uri')" |
  curl --fail-with-body --silent --show-error \
    --request POST \
    --header 'Content-Type: application/x-www-form-urlencoded' \
    --data-binary @- \
    https://id.sophos.com/api/v2/oauth2/token
)
unset SOPHOS_CLIENT_SECRET

SOPHOS_ACCESS_TOKEN=$(jq -er '
  select(.token_type == "bearer") |
  select((.expires_in | type) == "number" and .expires_in > 0) |
  .access_token | select(type == "string" and length > 0)
' <<<"$TOKEN_RESPONSE")
unset TOKEN_RESPONSE

A successful response contains at least access_token, token_type: "bearer", and expires_in; refresh_token, errorCode, message, and trackingId can also be present. expires_in is the lifetime in seconds. For client credentials, obtain a new access token when it expires rather than relying on the optional refresh token. Never log the response because both token fields are secrets.

Evaluate whoami

Pass the bearer header through curl’s standard-input configuration and retain only non-secret discovery fields:

WHOAMI=$(
  printf 'header = "Authorization: Bearer %s"\n' "$SOPHOS_ACCESS_TOKEN" |
  curl --fail-with-body --silent --show-error \
    --config - https://api.central.sophos.com/whoami/v1
)

SOPHOS_ID=$(jq -er '.id | select(type == "string" and length > 0)' <<<"$WHOAMI")
SOPHOS_ID_TYPE=$(jq -er '.idType | select(. == "tenant" or . == "partner" or . == "organization")' <<<"$WHOAMI")

A tenant response has this contract; placeholders are not production values:

{
  "id": "<tenant-uuid>",
  "idType": "tenant",
  "apiHosts": {
    "global": "https://api.central.sophos.com",
    "dataRegion": "https://api-us03.central.sophos.com"
  }
}

For idType: "tenant", validate and copy the tenant UUID and host:

UUID_RE='^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$'
SOPHOS_TENANT_ID=$(jq -er --arg re "$UUID_RE" '
  .id | select(type == "string" and test($re))
' <<<"$WHOAMI")
SOPHOS_API_HOST=$(jq -er '
  .apiHosts.dataRegion |
  select(type == "string" and test("^https://api-[a-z0-9-]+\\.central\\.sophos\\.com$"))
' <<<"$WHOAMI")

For idType: "partner" or "organization", whoami normally contains only apiHosts.global; SOPHOS_ID is not a tenant ID. The following bounded loop reads the list with the required context header and follows the documented pages.total value. Each tenant object supplies its own id and apiHost. Select the target by an UUID from a trusted internal mapping, never only by a similar display name.

case "$SOPHOS_ID_TYPE" in
  partner)
    TENANTS_URL='https://api.central.sophos.com/partner/v1/tenants'
    CONTEXT_HEADER="X-Partner-ID: ${SOPHOS_ID}"
    ;;
  organization)
    TENANTS_URL='https://api.central.sophos.com/organization/v1/tenants'
    CONTEXT_HEADER="X-Organization-ID: ${SOPHOS_ID}"
    ;;
  *) printf 'This list is only for partner or organization credentials.\n' >&2; exit 1 ;;
esac

TENANTS_FILE=$(mktemp)
printf '[]\n' >"$TENANTS_FILE"
page=1
max_pages=1000
expected_pages=
while (( page <= max_pages )); do
  PAGE_RESPONSE=$(
    printf 'header = "Authorization: Bearer %s"\n' "$SOPHOS_ACCESS_TOKEN" |
    curl --fail-with-body --silent --show-error --get \
      --config - --header "$CONTEXT_HEADER" \
      --data-urlencode "page=${page}" \
      --data-urlencode 'pageSize=100' \
      --data-urlencode 'pageTotal=true' \
      "$TENANTS_URL"
  )
  page_total=$(jq -er '
    select((.items | type) == "array") |
    .pages.total | select(type == "number" and floor == . and . >= 1 and . <= 1000)
  ' <<<"$PAGE_RESPONSE")
  if [[ -z "$expected_pages" ]]; then expected_pages=$page_total; fi
  [[ "$page_total" == "$expected_pages" ]] || { printf 'Pagination changed during retrieval.\n' >&2; exit 1; }
  jq -e --argjson page "$PAGE_RESPONSE" '. + $page.items' \
    "$TENANTS_FILE" >"${TENANTS_FILE}.new"
  mv "${TENANTS_FILE}.new" "$TENANTS_FILE"
  (( page >= expected_pages )) && break
  ((page++))
done
(( page == expected_pages )) || { printf 'Tenant pagination exceeded its bound.\n' >&2; exit 1; }
unset PAGE_RESPONSE

read -r -p 'Target tenant UUID from the approved mapping: ' TARGET_TENANT_ID
TARGET_TENANT=$(jq -cer --arg id "$TARGET_TENANT_ID" --arg re "$UUID_RE" '
  [.[] | select((.id | type) == "string" and (.id | test($re)) and
                (.id | ascii_downcase) == ($id | ascii_downcase)) |
         select((.apiHost | type) == "string" and
                (.apiHost | test("^https://api-[a-z0-9-]+\\.central\\.sophos\\.com$")))] |
  select(length == 1) | .[0]
' "$TENANTS_FILE")
SOPHOS_TENANT_ID=$(jq -r '.id' <<<"$TARGET_TENANT")
SOPHOS_API_HOST=$(jq -r '.apiHost' <<<"$TARGET_TENANT")
export SOPHOS_TENANT_ID SOPHOS_API_HOST
rm -f "$TENANTS_FILE"
unset TARGET_TENANT TARGET_TENANT_ID TENANTS_FILE TENANTS_URL CONTEXT_HEADER
unset page page_total expected_pages max_pages

Every tenant product request in this regional REST workflow then couples three values: the bearer token, X-Tenant-ID: <Tenant-UUID> and that tenant’s regional apiHost. Do not substitute the global host for a regional REST product API. An API-specific GraphQL target host is separate. scope=token does not authorize product operations; role, tenant access, licence and the specific endpoint also determine authorization.

Validation and controlled recovery

Before writing, call a harmless read endpoint in the target API and verify the expected idType, tenant UUID, approved host format, valid JSON, complete pagination, and expected objects. Also confirm an expressly prohibited test is rejected with 403 without causing a production change. Clear session variables afterwards:

unset SOPHOS_ACCESS_TOKEN SOPHOS_CLIENT_ID SOPHOS_ID SOPHOS_ID_TYPE
unset SOPHOS_TENANT_ID SOPHOS_API_HOST WHOAMI

If tenant or host is wrong, stop immediately, send no write requests, and isolate or delete any returned cross-tenant data according to policy. Reverse an existing product change through its pre-planned product-specific rollback. Deleting a credential revokes future API calls but does not undo a change.

Troubleshoot shared API access

  • 400: check form encoding, required fields, grant_type=client_credentials, and scope=token.
  • 401: check credential existence and expiry, latest secret set, token, and bearer syntax; then authenticate once more.
  • 403: identity is authenticated but lacks the role, tenant approval, or operation permission. Do not grant Super Admin by default.
  • 404: check global versus regional host, API version, and path; do not probe regions.
  • 429: honor Retry-After and retry a bounded number of times with backoff and jitter.
  • 5xx: retain request ID or trackingId, timestamp, method, and redacted path, then retry within a bound; never copy a secret or token into a support case.
  • Unexpected idType or missing apiHost: do not construct tenant headers. Check credential type and the fully paginated partner or Enterprise tenant list.

Test authentication in a controlled manner

The first test is not a production write action. For the regional REST test shown here, first obtain an OAuth access token from the Sophos identity endpoint. The whoami endpoint then returns identity, account type and, for tenant credentials, the regional API host; partner and organization credentials require the tenant list. Only then perform a harmless read request against the REST API host returned for that tenant.

Do not copy a regional REST API host from an example. For this contract, use the URL returned by whoami or the tenant list; Search GraphQL uses the separate target host described above. Tenant ID and organization ID are not interchangeable either.

Document at least these test cases:

  • Authentication with the new identity succeeds.
  • The expected tenant is returned.
  • Permitted read operations succeed.
  • A prohibited operation is rejected with 403 Forbidden.
  • The target system records the test traceably without logging the Client Secret.

Operate expiration and rotation

Sophos does not send a warning when an API credential expires. Once expired, it can no longer authenticate and is automatically removed from Sophos Fusion. Expiration monitoring must therefore take place outside Sophos Fusion.

A clean rotation process uses a short overlap:

  1. Create a new credential with the same or a narrower role.
  2. Move the application to the new Client ID and secret.
  3. Test authentication and the application’s business function.
  4. Delete the old credential.
  5. Verify the change in the secret register and operating documentation.

Do not leave the old credential active for months as a precaution. If an application supports only one secret set, schedule a maintenance window.

Replace legacy SIEM API tokens

API Token Management is the former authentication method for the SIEM Integration API. Sophos no longer issues new tokens there and does not extend existing lifetimes. Existing tokens work only until they expire.

Do not leave an integration on this method until the last day. Inventory its token, target system, expiration date, and endpoints; create an appropriate API credential; migrate the application; and verify the complete data flow. Remove the old token only after successful parallel verification.

Moving from a legacy token to API credentials is more than a rename. The integration must support OAuth authentication, whoami, the regional host, and the role model. Configure a SIEM connector from its current vendor instructions, not from an old token example.

External service providers and third-party access

Create a dedicated Service Principal Read-Only identity for an external party when read access is sufficient. Transfer the Client ID and secret through separate, encrypted channels. Record a firm end date and delete the access when the project ends.

Through the API, such third-party access can read Alerts and Events, Account Health Check results, device details, and policy configurations. Read-Only prevents adding, changing, and deleting data in Sophos Fusion, but does not limit what readable data the third-party platform retrieves or stores. Before approval, contractually define data scope, purpose, storage location, retention, and deletion.

Creation follows Global Settings > Access Control > API Credentials > Add Credential. Accept the use and privacy terms on first access, select Service Principal Read-Only, and immediately secure the Client ID and the one-time Client Secret. Transfer them through an approved encrypted channel, such as the provider’s HTTPS portal, never by email or in ticket text.

Do not copy the API host from a static regional table. The application must use whoami to discover the API host valid for that specific tenant. This keeps the integration correct even if Sophos changes regions or endpoints. Delete the credential as soon as the third party no longer needs access; this immediately revokes the API authorization.

Exporting a personal Super Admin account, sharing one API identity across customers, or placing a secret in a support ticket is unacceptable. The service provider must also disclose where the secret is stored, how it is protected, and when it is deleted.

Troubleshoot methodically

401 Unauthorized

The Client ID, secret, token endpoint, or OAuth request is usually incorrect. An expired and already removed credential produces the same error. First verify that the credential still exists in Sophos Fusion and that the application uses the latest secret set.

403 Forbidden

Authentication succeeded, but the role does not permit the action. Instead of immediately granting Super Admin, map the required API endpoint to the appropriate service principal role.

Correct token, wrong data region

The access token alone does not determine the product API host. For a regionally routed REST product API, the application must use the regional host returned by whoami or the tenant list; Search GraphQL uses its own target contract. A hard-coded host from another region causes errors or queries across the wrong platform boundary.

Integration fails without a warning

If Sophos Fusion has no open alert, check the expiration date, last successful API request, and secret version in the target system. Expiration monitoring belongs in external monitoring.

Regular review

At least quarterly, review the name, owner, role, last use, expiration, and target system of every credential. Delete identities that cannot be assigned or are no longer used. If secret exposure is suspected, immediately delete the affected credential and replace it. Then inspect the target-system and integration logs for unusual API calls.

Review personal administrator permissions separately according to Assign Sophos Fusion administrator roles correctly. API credentials replace neither MFA nor personal, accountable administrator access.

Frequently asked questions

Can an existing Client Secret be displayed again?

No. The secret is visible only immediately after creation. If it is lost, create and test a new credential, then delete the old one.

Which role is appropriate for a SIEM that only reads data?

Usually Service Principal Read-Only. If the integration requires specific forensic or write actions, assess them individually and implement them through an appropriate separate identity.

Does Sophos Fusion warn before expiration?

No. Expiration must be monitored in the secret register or monitoring system. After expiration, authentication is no longer possible and the credential is automatically removed.