Skip to main content

Authentication

The Zscaler SDK uses OAuth 2.0 to authenticate with credentials issued by Authentication Service. A single Session authenticates against all supported products, such as Authentication Service, Client Connector, Cloud & Branch Connector ZDX, ZIA, and ZPA.

Client Credentials

You can create and manage API clients in the Zscaler Admin Console. The Getting Started guide provides a walkthrough of the full onboarding flow. To learn more about API client configuration, see About API Clients Adding an API Client.

From an API client, you obtain:

  • Client ID: The public identifier for the API client
  • Client Secret: A confidential shared secret (alternatively, a certificate or private key for JWT bearer authentication)
  • Vanity domain: Your organization's subdomain assigned when your Authentication Service tenant was provisioned (for example, if your login URL is https://acme.zslogin.net, your subdomain is acme). It is not a full hostname.

Explicit Authentication​

Pass the credentials directly to Session(). No cloud parameter is required in the production environment.

import os
from zssdk import Session

session = Session(
vanity_domain="acme",
client_id=os.environ["ZSCALER_CLIENT_ID"],
client_secret=os.environ["ZSCALER_CLIENT_SECRET"],
)

# Every product is accessible from the same session
for user in session.zia.admin_users.all():
print(user.name)

Implicit Authentication​

The SDK can automatically discover credentials from ZSCALER_* environment variables, so you can keep them out of code.

export ZSCALER_VANITY_DOMAIN="acme"
export ZSCALER_CLIENT_ID="your_client_id"
export ZSCALER_CLIENT_SECRET="your_client_secret"
from zssdk import Session
session = Session() # picks up credentials from env vars

Use ZSCALER_* variables for credentials and ZSSDK_* variables for SDK behavior. For a complete list of variables, see the Configuration guide.

Configuration File​

You can store credentials in ~/.zscaler/config (INI format) and select a profile when creating the session:

# ~/.zscaler/config
[default]
vanity_domain = acme
client_id = your_client_id
client_secret = your_client_secret
from zssdk import Session
session = Session(profile_name="default")

For a complete precedence chain (constructor arguments → instance variables → environment variables → config file → defaults), see the Configuration guide.

Beta Environment​

The only valid explicit value for the cloud parameter is beta, which points the SDK to the Authentication Service beta environment (zsloginbeta.net). Omit cloud entirely in the production environment.

Legacy cloud names (e.g., zscalerone.net, zscalertwo.net) are not supported by the SDK.

from zssdk import Session

# Authentication Service beta environment (non-production testing only)
session = Session(
cloud="beta",
vanity_domain="acme",
client_id=os.environ["ZSCALER_CLIENT_ID"],
client_secret=os.environ["ZSCALER_CLIENT_SECRET"],
)

JWT Bearer Authentication

For stronger security, authenticate with a private key instead of a shared secret.

Using a Private Key File​

import os
from zssdk import Session

session = Session(
vanity_domain="acme",
client_id=os.environ["ZSCALER_CLIENT_ID"],
cert_file_path="/path/to/private_key.pem",
)

Using a Private Key String​

import os
from zssdk import Session

session = Session(
vanity_domain="acme",
client_id=os.environ["ZSCALER_CLIENT_ID"],
private_key="-----BEGIN RSA PRIVATE KEY-----\n...\n-----END RSA PRIVATE KEY-----",
)

Custom Token Provider​

If you already obtain tokens from an external identity system (for example, a secrets-management service or another OAuth provider), you can plug in a custom token provider:

from zssdk import Session

class MyTokenProvider:
"""Implements the TokenProvider protocol."""

def get_token(self) -> str:
# Fetch token from your own identity provider
return "your-jwt-token"

def get_expiration_time(self) -> int:
# Unix timestamp when the token expires
return 1700000000

session = Session(
vanity_domain="acme",
token_provider=MyTokenProvider(),
)

Token Lifecycle

The SDK manages tokens automatically after the session is created. The token is:

  • Issued on first request (lazy), and no upfront token fetch takes place.
  • Cached between requests for the token's lifetime (up to 24 hours per Authentication Service).
  • Refreshed transparently when the token is within a 5‑minute expiry buffer.
  • Thread-safe using double-checked locking.
Distinction between token lifetime and product session

The Authentication Service token lifetime (up to 24 hours) is independent of each backend product's session concept. For example, ZIA maintains a separate backend session with its own (short) timeout; the SDK does not own or expose that. To learn more about the distinction, see Session Management.

Multiple Sessions

A single session authenticates against all supported products, but you can create multiple sessions to target different tenants or environments simultaneously.

from zssdk import Session

# Two independent tenants — each with its own Authentication Service credentials
tenant_a = Session(profile_name="tenant-a")
tenant_b = Session(profile_name="tenant-b")

for role in tenant_a.zia.admin_roles.all():
print("tenant A:", role.name)

for role in tenant_b.zia.admin_roles.all():
print("tenant B:", role.name)

Advanced Configuration

Proxy settings, timeouts, Federal Information Processing Standards (FIPS) endpoints, and logging—all attach to the session through a Config object.

Proxy​

from zssdk import Session
from zssdk.zscore.config import Config, Proxy

config = Config(
proxy=Proxy(
host="proxy.company.com",
port=8080,
username="proxy-user", # optional
password="proxy-password", # optional
)
)

session = Session(
vanity_domain="acme",
client_id="your-client-id",
client_secret="your-client-secret",
config=config,
)

Timeouts and Connection Pool​

from zssdk import Session
from zssdk.zscore.config import Config, HttpConnection

config = Config(
http_connection=HttpConnection(
connect_timeout=30.0,
read_timeout=60.0,
write_timeout=30.0,
pool_timeout=10.0,
max_connections=200,
max_keepalive_connections=50,
keepalive_expiry=30.0,
)
)

session = Session(
vanity_domain="acme",
client_id="your-client-id",
client_secret="your-client-secret",
config=config,
)

FIPS Endpoints​

For FIPS-compliant production deployments, enable the FIPS flag in Config. This selects the FIPS variant of each service's endpoint where available.

from zssdk import Session
from zssdk.zscore.config import Config

config = Config(use_fips_endpoint=True)

session = Session(
vanity_domain="acme",
client_id="your-client-id",
client_secret="your-client-secret",
config=config,
)

Security Best Practices

For the best results:

  • Do not hard code credentials in source control; use environment variables or a secrets manager instead.
  • Rotate the client_secret (or the private key) on a schedule appropriate for your environment.
  • Use least-privilege scopes when creating API clients in Authentication Service.
  • Prefer JWT bearer authentication (cert_file_path or private_key) over static secrets for production.
  • Store private keys with 0600 permissions.
  • Enable logging with logging_format="json" in the production environment. Credentials and Authorization headers are redacted automatically.

Troubleshooting

If authentication fails, enable verbose logging to examine the request and response. Credentials and bearer tokens are redacted automatically.

from zssdk import Session
from zssdk.zscore.config import Config, LoggerConfig

logger_config = LoggerConfig(
enabled=True,
verbose=True,
log_to_file=True,
log_file_path="auth_debug.log",
)
config = Config(logger_config=logger_config)

try:
session = Session(
vanity_domain="acme",
client_id="your-client-id",
client_secret="your-client-secret",
config=config,
)
# Any API call triggers token acquisition
list(session.zid.api_clients.all())
except Exception as e:
print(f"Authentication failed: {e}")
print("Check:")
print(" - Client ID and Client Secret are correct and active in Authentication Service")
print(" - `vanity_domain` matches your Authentication Service tenant (subdomain only)")
print(" - If targeting the beta environment, `cloud=\"beta\"` is set")
print(" - The API client has scopes for the product you're accessing")
print(" - Network connectivity to `{vanity_domain}.zslogin.net`")

Related

  • Getting Started: End-to-end onboarding, including creating an API client in the Zscaler Admin Console.
  • Configuration: Configuration file format, environment variables, and precedence chain.
  • Session Management: Session lifecycle and its distinction from backend product sessions.
  • Logging: Log formats and automatic credential redaction.