Skip to content
Avanet

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

Every Sophos Central API starts with the same sequence. The global identity host issues the OAuth token; the global whoami host identifies the credential. Tenant product requests then go only to the regional host returned for that tenant. Allow these required HTTPS targets from the administration or integration system:

  • 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.

Never infer a region or copy it from a static table. Accept only the complete HTTPS host supplied by Sophos, then append the path from the selected API’s contract.

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' \
    "$(jq -rn --arg v "$SOPHOS_CLIENT_ID" '$v|@uri')" \
    "$(jq -rn --arg v "$SOPHOS_CLIENT_SECRET" '$v|@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 couples exactly three values: Authorization: Bearer <access-token>, X-Tenant-ID: <tenant-uuid>, and that tenant’s regional apiHost. Do not substitute the global host for a regional product API. scope=token does not authorize product operations; role, tenant access, licence, and the selected endpoint also apply.

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 must not be a production write action. First obtain an OAuth access token from the Sophos identity endpoint. The whoami endpoint then returns the tenant ID, API host, and account data type. Only then perform a harmless read request against the API host supplied for that tenant.

Do not copy an API host from an example. Sophos operates multiple data regions, so the URL returned by whoami must be used. Tenant ID and organization ID are also not interchangeable.

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 select the business API host. The application must use the regional host returned by whoami. 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.