wif.tax

Zscaler

C Zscaler OneAPI (ZIA, ZPA and other APIs via ZIdentity API clients)

OneAPI clients in ZIdentity get one-hour tokens by OAuth client credentials, using a client secret or a private-key JWT checked against keys you upload or host at a JWKS URL. Every path starts from a long-lived secret you hold, and no external OIDC token is accepted. Secrets expire within 365 days, rotate by API and are role-scoped; there is no GitHub partner revocation. Into AWS and GCP it is keyless; Azure wants a client secret.

Docs: automate.zscaler.com · Checked 2026-10-22 · source YAML · dispute via PR

Inbound Crequires ZIdentity (Authentication Service) subscription for OneAPI

How a workload running anywhere authenticates to this product.

OAuth 2.0 client_credentials at <vanity>.zslogin.net with a ZIdentity API client authenticated by a client secret (SECRET), a private_key_jwt assertion checked against an uploaded public key or certificate (PUBKEYCERT), or a JWKS URL you host (JWKS). Tenants not yet on ZIdentity use the legacy per-product credentials: ZIA API key plus admin username and password, ZPA client ID and secret.

Graded on OneAPI, the path Zscaler steers all new automation to (ZIA, ZPA, ZDX, Client Connector, Cloud & Branch Connector, EASM and more behind one token endpoint). All three ZIdentity client authentication methods start from a static root you hold: a shared secret, or an RSA private key whose public half you upload or publish at a JWKS URL. The JWKS option makes rotation of your own key painless, but the assertion is self-issued (iss and sub are the client ID), so it is private_key_jwt, not federation: there is no token exchange, no trust in GitHub Actions or cloud workload identity tokens, and no subject matching. The SDK's custom TokenProvider hook only lets you supply a ZIdentity token you already obtained. Nearest thing to federation: the legacy ZIA cloud service API can trust one external OAuth authorization server (documented for Okta, Entra ID and PingFederate) by JWKS URL with optional aud, iss and client_id checks and a scope claim naming a ZIA API role, which in principle lets an Entra app with a federated credential call ZIA keylessly. It does not lift this grade: it covers the ZIA cloud service API only (not ZPA, OneAPI or the Sandbox API), only one server can be enabled at a time, there is no subject constraint, and the documented flow uses a client secret at the IdP. Legacy credentials for tenants not on ZIdentity are weaker still: one org-wide ZIA API key combined with an admin's username and password, and ZPA client ID/secret pairs; the ZIA Sandbox submission API uses its own static token. Inbound moves to B or A only if ZIdentity accepts tokens from an external OIDC issuer (token exchange or a federated credential on the API client).

Outbound B

How this product reaches into your cloud, repos, or other SaaS.

Cloud & Branch Connector workload discovery assumes an IAM role you create (with an External ID) that trusts Zscaler's AWS role, and on GCP impersonates your service account via Service Account Token Creator. Azure workload discovery, the Microsoft Defender for Cloud Apps integration and Cloud NSS SIEM feeds take a client secret from your Entra app or a static token in an HTTP header.

Checked: Cloud & Branch Connector partner integrations (workload and tag discovery) on AWS (role with External ID trusting Zscaler's account, created by CloudFormation; keyless), GCP (Zscaler's service account impersonates yours via roles/iam.serviceAccountTokenCreator; keyless) and Azure (Limited Availability; you register a single-tenant Entra app, create a client secret and paste tenant ID, client ID and secret into Zscaler; static); the ZIA Microsoft Defender for Cloud Apps (MCAS) integration (Entra app client secret; static); ZIA Cloud NSS feeds to cloud SIEMs (API URL plus header tokens such as a Splunk HEC token, or OAuth 2.0 client credentials for SIEMs that use it; static); and ZPA Log Streaming Service (your own App Connector pushes to your receiver over TCP or mTLS; no credential handed over). Cloud & Branch Connector VMs themselves run in your account with their own instance identity and provisioning keys, which are not Zscaler reaching in. An Azure federated credential or multi-tenant app consent for discovery and MCAS, and keyless SIEM delivery, would lift outbound to A.

Hygiene for any static credential the product still issues

✓ Expiry enforceable
ZIdentity client secrets always carry an expiry, capped by the platform at 365 days, and expiresAt is a required field when adding a secret by API. That is an enforced maximum, not a changeable default (contrast elastic-cloud-api). Uploaded public keys and JWKS URLs have no Zscaler-side expiry, but the private key never leaves you. Legacy ZIA API keys and ZPA client secrets have no documented expiry (ZPA's "Session Validity Interval" is the token lifetime, max 3,600 seconds).
  • help.zscaler.com checked 2026-10-22
    “The minimum duration is 30 days and the maximum duration is 365 days.”
  • automate.zscaler.com checked 2026-10-22
    “The expiration time of the client secret, represented as a UNIX epoch timestamp (in seconds).”
✓ Rotation via API
The ZIdentity API has POST and DELETE on /api-clients/{id}/secrets plus create, update and delete for API clients themselves, and two concurrent secrets allow overlap during rotation.
✓ Scoped keys
API clients are purpose-built machine principals, each given one API role per Zscaler service (roles defined in that service, e.g. read-only), and an API client access policy can further restrict resources and time windows. The legacy ZIA path inherits the full rights of the admin whose password is used.
  • automate.zscaler.com checked 2026-10-22
    “API Clients can be assigned one resource per product, which defines what that client can do (i.e., read, write, or restricted access).”
  • help.zscaler.com checked 2026-10-22
    “Scope refers to the permission that limits the access to specific API resources.”
✓ Last-used visible
Judgment call. Neither the API Clients page (name, status, client ID) nor the secrets API (id, createdAt, expiresAt) has a last-used field, but the Tokens page lists every token ZIdentity issued, searchable by client ID with an Issued At time, which shows when each client last authenticated and exposes clients that never do. It is per client, not per secret. If reviewers want a last-used field on the credential itself, flip this to fail.
  • help.zscaler.com checked 2026-10-22
    “View the list of client IDs and the assigned tokens.”
  • help.zscaler.com checked 2026-10-22
    “View the tokens that were issued in the selected time frame.”
  • automate.zscaler.com checked 2026-10-22
    “Timestamp when the secret was created.”
✗ Leak revocation
Zscaler does not appear in GitHub's supported secret scanning patterns table at all, so a ZIdentity client secret (or legacy ZIA API key or ZPA secret) pushed to a public repo is not reported to Zscaler.

Notes

One card for Zscaler's API surface: OneAPI through ZIdentity (Authentication Service), with the legacy per-product ZIA and ZPA credentials noted for tenants not yet migrated. Not split, per brief. Hygiene applies to ZIdentity client secrets. Four of five checks pass (last_used is a judgment call, see above); GitHub partner revocation would make five. Inbound is held at C by the absence of any external-issuer trust in ZIdentity.

Badge

wif.tax grade C

[![wif.tax grade](https://wif.tax/badge/zscaler-oneapi.svg)](https://wif.tax/p/zscaler-oneapi/)