Skip to content

Managing Service Accounts

Service Accounts are created and managed exclusively by users with the Super Admin role. Navigate to Admin → Service Accounts to access the management interface.

Creating a Service Account

Navigate to Admin → Service Accounts → Add to create a new account. You will be prompted to provide:

Field Required Notes
Name Yes A human-readable label, e.g. CI/CD Pipeline — Prod
Description No Optional notes for operators
Status Yes Active or inactive; defaults to active
Scopes Yes One or more of read, write, admin
Allowed IP Addresses No One IP or CIDR range per line; leave empty to allow all IPs
Expiry Date No Must be a future date if set

When the account is created, the client_id and client_secret are displayed once only in a dismissible confirmation dialog. Store both values securely — the secret cannot be retrieved after dismissal. If lost, you must regenerate a new secret from the account's management page.

Viewing and Editing an Account

Open an account from the Service Accounts list to view its details. All fields except client_id can be edited:

  • Name and description can be updated at any time.
  • Status can be toggled between active and inactive.
  • Scopes can be modified to expand or restrict access.
  • Allowed IP addresses can be updated to add or remove IPs and CIDR ranges.
  • Expiry date can be set, changed, or cleared.

All changes are recorded in the audit log with the previous and updated values.

Regenerating a Secret

Open the account from the Service Accounts list and use the Regenerate Secret action. The new secret is displayed once in a confirmation dialog; the previous secret is immediately invalidated.

Any active sessions authenticated with the old secret continue to work until they expire. Sessions are not invalidated on secret regeneration — revoke them explicitly if immediate revocation is required.

Disabling an Account

Set the account status to inactive to suspend access without removing the account or its audit history. All subsequent authentication attempts will be rejected with SERVICE_ACCOUNT_INACTIVE.

Active sessions for a disabled account are immediately invalidated — the session validation middleware checks the account's current status on each request.

Deleting an Account

Use the Delete action on the account's management page to permanently remove the account. All active sessions for the account are immediately invalidated.

Deletion is permanent. If you want to preserve the audit history and the option to re-enable access later, disable the account instead.

Audit Log

All Service Account management operations are recorded in the platform audit log:

Event Trigger
service_account.created Account created
service_account.updated Account fields modified (includes old and new values)
service_account.secret_regenerated Client secret regenerated
service_account.deleted Account permanently deleted
service_account.authenticated Successful authentication
service_account.session_revoked Session explicitly revoked

Managing Couriers via API

Service Accounts with write scope can create and manage Courier records programmatically. This is the primary integration point for Terraform providers and infrastructure-as-code pipelines that need to provision Couriers alongside the systems they serve.

All Courier management endpoints are prefixed /api/v1/service/couriers and require a valid session token.

Endpoints

Method Path Required Scope Description
GET /api/v1/service/couriers read List all Couriers for the tenant
GET /api/v1/service/couriers/{uuid} read Get a single Courier by UUID
POST /api/v1/service/couriers write Create a Courier
PUT /api/v1/service/couriers/{uuid} write Update a Courier
DELETE /api/v1/service/couriers/{uuid} write Delete a Courier

All resources are identified by UUID. Internal integer IDs are never exposed.

Important Behaviours

Authentication method is immutable. Once a Courier is created, its auth_method cannot be changed via the API or the portal. To change the authentication method, delete the Courier and recreate it. In Terraform, auth_method is a ForceNew attribute.

Client secret is returned once. For client_secret authentication, the client_id is auto-generated and included in all read responses. The client_secret is returned only in the POST creation response. Store it securely — it cannot be retrieved again. To rotate, use the portal's Regenerate Secret action.

PKI certificate not returned in reads. For pki_certificate authentication, the full PEM certificate is accepted on create and update but never returned in API responses. Only the certificate_fingerprint (SHA-256) is returned.

Domain validation is format-only. The portal validates allowed_domains against the tenant's registered domains. The API accepts any syntactically valid domain pattern without requiring the domain to be pre-registered. This allows Terraform workflows where Courier configuration is applied before domain registration.

Tenant limits are enforced. Creating a Courier when the tenant has reached its Courier limit returns 403 LIMIT_REACHED.

Create a Courier

POST /api/v1/service/couriers
Authorization: Bearer <token>
Content-Type: application/json

Request body:

{
  "name": "Production Courier",
  "description": "Pulls certs for prod k8s cluster",
  "owner": "platform-team",
  "contact_email": "[email protected]",
  "status": "active",
  "auth_method": "client_secret",
  "allowed_domains": ["*.prod.example.com"]
}

Success response (201 Created):

{
  "success": true,
  "message": "Courier created successfully. Store the client_secret securely - it cannot be retrieved again.",
  "data": {
    "uuid": "550e8400-e29b-41d4-a716-446655440000",
    "name": "Production Courier",
    "description": "Pulls certs for prod k8s cluster",
    "owner": "platform-team",
    "contact_email": "[email protected]",
    "status": "active",
    "auth_method": "client_secret",
    "allowed_domains": ["*.prod.example.com"],
    "client_id": "cour_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "client_secret": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "last_seen_at": null,
    "last_ip_address": null,
    "request_count": 0,
    "created_at": "2026-04-14T10:00:00+00:00",
    "updated_at": "2026-04-14T10:00:00+00:00"
  }
}

Subsequent GET responses for client_secret Couriers include client_id but omit client_secret.

Authentication Method Configurations

The auth_method field and its corresponding auth_config or client_certificate field determine how the Courier will authenticate at runtime.

client_secret — no auth_config required; credentials are auto-generated:

{ "auth_method": "client_secret" }

azure_jwt — for workloads on Azure with a managed identity or workload identity:

{
  "auth_method": "azure_jwt",
  "auth_config": {
    "tenant_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "client_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "allowed_audiences": "api://my-app"
  }
}

azure_arc — for on-premises servers enrolled in Azure Arc:

{
  "auth_method": "azure_arc",
  "auth_config": {
    "tenant_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "allowed_resource_ids": "/subscriptions/*/resourceGroups/prod/*",
    "require_tag_validation": true
  }
}

oidc_oauth2 — for generic OIDC identity providers (including AWS IAM OIDC):

{
  "auth_method": "oidc_oauth2",
  "auth_config": {
    "issuer": "https://accounts.google.com",
    "client_id": "my-client-id",
    "allowed_audiences": ""
  }
}

spiffe_spire — for workloads with a SPIRE agent:

{
  "auth_method": "spiffe_spire",
  "auth_config": {
    "trust_domain": "example.org",
    "allowed_spiffe_ids": "spiffe://example.org/service/app,spiffe://example.org/service/worker"
  }
}

pki_certificate — for X.509 client certificate authentication:

{
  "auth_method": "pki_certificate",
  "client_certificate": "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----"
}

Only certificate_fingerprint (SHA-256) is returned in responses; the full certificate is not.

Error Codes

Code HTTP Meaning
COURIER_NOT_FOUND 404 Courier UUID not found in this tenant
LIMIT_REACHED 403 Tenant Courier limit exceeded
AUTH_METHOD_IMMUTABLE 422 Attempt to change auth_method after creation
INVALID_CERTIFICATE 422 client_certificate is not a valid PEM X.509 certificate
VALIDATION_ERROR 422 Invalid request body or missing required auth_config fields
INSUFFICIENT_SCOPE 403 Write operation attempted with a read-only token
INTERNAL_ERROR 500 Unexpected server error