Service accounts are non-human, programmatic identities that allow scripts, devices, and external integrations to authenticate to Crosswork Assurance without using a human user's credentials. Each service account is a machine user scoped to your tenant organization.
Controlled Availability: Service Accounts is a controlled availability feature for on-premise installations only.
Overview
Use service accounts when you need to:
Stream data exports — External gNMI clients or Kafka consumers authenticating to Analytics Streamer
Automate API access — Scripts, CI/CD pipelines, or external tools that need programmatic access
Integrate third-party systems — SIEMs, BI tools, or data lakes consuming Crosswork Assurance telemetry
Each service account can have one or more Personal Access Tokens (PATs) that serve as bearer tokens for authentication.
Best Practice: Create one service account per external integration so that credentials can be issued, scoped, audited, and revoked independently.
Prerequisites
You must have the
skylight-adminortenant-adminroleRoles granted to a service account cannot exceed your own roles
Note: There are no enforced limits on the number of service accounts or PATs per tenant.
Create a Service Account
Using the UI
Navigate to Accounts > Service users tab.

Click the + button to create a new service user.
Complete the form:
Name — Human-readable display name
Username — Unique identifier for the service account
Description — (Optional) Purpose of the service account
Access token type — Select
BearerAnalytics role — Select the appropriate role:
skylight-admin,tenant-admin, orservice-account-manager
(Optional) To create a PAT at the same time:
Check Create with PAT
Set an Expiration date (must be in the future)

Click the checkmark button to create.
Important: If you created a PAT, click Copy to clipboard immediately. The PAT value is only displayed once and cannot be retrieved later.

Using the API
curl --request POST \
--url '{baseUrl}/api/v2/auth/serviceaccount?withPAT=true&roles=tenant-admin' \
--header 'Authorization: Bearer {yourToken}' \
--header 'Content-Type: application/json' \
--header 'X-Forwarded-Tenant-Id: {tenantId}' \
--data '{
"username": "streamer-export",
"name": "Streamer Export",
"accessTokenType": "Bearer",
"description": "Used by analytics streamer for gNMI export",
"expirationDate": "2026-12-31T23:59:59Z"
}'Request body fields:
Field | Required | Description |
|---|---|---|
| Yes | Unique identifier within your tenant |
| Yes | Human-readable display name |
| Yes | Set to |
| No | Free text description (max 400 characters) |
| Only with | RFC 3339 timestamp for PAT expiry |
Query parameters:
Parameter | Description |
|---|---|
| Set to |
| Comma-separated roles to assign: |
Example response:
{
"machineUserId": "291606795498498048",
"username": "streamer-export",
"name": "Streamer Export",
"description": "Used by analytics streamer for gNMI export",
"pat": "ZXlKaGJHY2lPaUpTVXpJMU5pSXNJblI1Y0NJNklr..."
}Important: The
patfield is only returned whenwithPAT=true. This is your only opportunity to capture the token value — it cannot be retrieved later.
Manage Personal Access Tokens (PATs)
A PAT is an opaque bearer token that you include in the Authorization header of API requests:
Authorization: Bearer <PAT>Add a PAT to an Existing Service Account
Using the UI
Navigate to Accounts > Service users tab.
Select the service account from the list.
Under Personal tokens, click Add.

Set an Expiration date (must be in the future).

Click Create.
Click Copy to clipboard to capture the PAT value before leaving the screen.

Using the API
curl --request POST \
--url '{baseUrl}/api/v2/auth/serviceaccount/{machineUserId}/pat' \
--header 'Authorization: Bearer {yourToken}' \
--header 'Content-Type: application/json' \
--header 'X-Forwarded-Tenant-Id: {tenantId}' \
--data '{
"expirationDate": "2026-12-31T23:59:59Z"
}'Example response:
{
"credentialId": "291606795498498200",
"machineUserId": "291606795498498048",
"expirationDate": "2026-12-31T23:59:59Z",
"pat": "ZXlKaGJHY2lPaUpTVXpJMU5pSXNJblI1Y0NJNklr..."
}List PATs
curl --request POST \
--url '{baseUrl}/api/v2/auth/serviceaccount/{machineUserId}/pat/search?page=1&pageSize=25' \
--header 'Authorization: Bearer {yourToken}' \
--header 'Content-Type: application/vnd.api+json' \
--header 'X-Forwarded-Tenant-Id: {tenantId}'Note: The search endpoint returns metadata only (creation date, expiration date, credential ID) — never the token value.
Delete a PAT
Deleting a PAT revokes it immediately. Any integrations using that PAT will lose access.
Using the UI
Navigate to the service account's detail page.
Under Personal tokens, click the trash icon next to the PAT you want to delete.

The PAT is deleted and a confirmation message appears.

Using the API
curl --request DELETE \
--url '{baseUrl}/api/v2/auth/serviceaccount/{machineUserId}/pat/{credentialId}' \
--header 'Authorization: Bearer {yourToken}' \
--header 'X-Forwarded-Tenant-Id: {tenantId}'Manage Service Accounts
Search Service Accounts
curl --request POST \
--url '{baseUrl}/api/v2/auth/serviceaccount/search?page=1&pageSize=25' \
--header 'Authorization: Bearer {yourToken}' \
--header 'Content-Type: application/vnd.api+json' \
--header 'X-Forwarded-Tenant-Id: {tenantId}' \
--data '{
"data": {
"attributes": {
"username": { "value": "streamer-export" }
}
}
}'Get a Service Account
curl --request GET \
--url '{baseUrl}/api/v2/auth/serviceaccount/{machineUserId}' \
--header 'Authorization: Bearer {yourToken}' \
--header 'X-Forwarded-Tenant-Id: {tenantId}'Update a Service Account
Update the name or description of an existing service account:
curl --request PATCH \
--url '{baseUrl}/api/v2/auth/serviceaccount/{machineUserId}' \
--header 'Authorization: Bearer {yourToken}' \
--header 'Content-Type: application/json' \
--header 'X-Forwarded-Tenant-Id: {tenantId}' \
--data '{
"name": "Streamer Export (Production)",
"description": "Updated description"
}'Delete a Service Account
Deleting a service account removes the machine user and revokes all of its PATs. Any integrations using those PATs will lose access.
curl --request DELETE \
--url '{baseUrl}/api/v2/auth/serviceaccount/{machineUserId}' \
--header 'Authorization: Bearer {yourToken}' \
--header 'X-Forwarded-Tenant-Id: {tenantId}'Use a PAT for Authentication
Once you have a PAT, include it in the Authorization header of your API requests:
curl --request GET \
--url '{baseUrl}/api/v2/some-endpoint' \
--header 'Authorization: Bearer {pat}' \
--header 'X-Forwarded-Tenant-Id: {tenantId}'Example: gNMI Streaming Client
gnmicli --addr tenant1.analytics.example.com:443 \
--query /accedian:session/object-type/twamp-sf/monitored-objects/... \
--auth token \
--authToken 'Bearer <PAT>'API Response Codes
Code | Meaning |
|---|---|
| Service account or PAT created successfully |
| Request successful |
| Invalid request body or path parameter |
| Caller lacks the required role, or requested roles exceed the caller's |
| Service account or PAT not found |
| A service account with this username already exists |
| Validation failed (for example, username conflicts with a human user) |
Troubleshooting
Common Errors
401 Unauthorized
Symptom: API requests fail with 401 Unauthorized.
Causes:
PAT is missing or malformed in the
AuthorizationheaderPAT has been deleted or revoked
Incorrect header format (must be
Bearer <PAT>, not just<PAT>)
Resolution:
Verify the PAT is included:
Authorization: Bearer <your-pat>Check if the PAT still exists in the service account's token list
If the PAT was deleted, create a new one and update your integration
403 Forbidden
Symptom: API requests fail with 403 Forbidden.
Causes:
PAT has expired
Service account lacks the required role for the requested operation
X-Forwarded-Tenant-Idheader is missing or incorrect
Resolution:
Check the PAT expiration date in the service account details
Verify the service account has the necessary roles assigned
Confirm the tenant ID matches your organization
409 Conflict
Symptom: Creating a service account fails with 409 Conflict.
Cause: A service account with the same username already exists.
Resolution: Choose a unique username, or search for the existing account and reuse it.
422 Unprocessable Entity
Symptom: Creating a service account fails with 422 Unprocessable Entity.
Cause: The username conflicts with an existing human user account.
Resolution: Choose a different username that doesn't match any human user in your tenant.
PAT Rotation Without Downtime
To rotate a PAT without interrupting your integration:
Create a new PAT on the existing service account (you can have multiple active PATs)
Update your integration with the new PAT
Verify the integration works with the new PAT
Delete the old PAT once the new one is confirmed working
Tip: Schedule PAT rotation before expiration. Set a calendar reminder for 30 days before each PAT expires.
Security Best Practices
Never commit PATs to source control — Use environment variables or a secrets manager
Store PATs securely — Use HashiCorp Vault, AWS Secrets Manager, Azure Key Vault, or similar
Set appropriate expiration dates — Balance security (shorter) with operational overhead (longer)
One service account per integration — Enables independent credential management and audit trails
Monitor for failed authentications — Repeated 401/403 errors may indicate credential issues or misuse
Related Topics
Authentication & Access
Obtain a Personal Access Token — Create PATs for human users via the Zitadel UI
Authentication Prerequisites — mTLS and PAT requirements for RESTCONF/gNMI
Identity & Access Management API — Full API reference
Integration Use Cases
Accessing Crosswork Assurance with gNMI — Stream telemetry data using PAT authentication
Working with the Agents Control API — Programmatic agent management
User & Device Management
Device Service Account Provisioning on Sensor Management — Automated device credential provisioning
Managing User Accounts — User roles and permissions
API Documentation Disclaimer
The APIs described in this document are for illustrative purposes. While efforts are made to keep this document current, always refer to the IAM API documentation for the authoritative source. Replace example values with those applicable to your environment.