Management API

Create and manage applications, API resources, secrets, and custom domains.

All endpoints are authenticated using the same OAuth 2.0 client credentials flow as any other AuthKnox API. See Authentication below.

Authentication

The management API uses AuthKnox itself for auth — the same client credentials flow your services use. During onboarding, AuthKnox creates a management application in your tenant and returns its credentials. Use those credentials to get a JWT targeting https://management.authknox.com, then send that JWT as a Bearer token on every management request.

Step 1 — get a management token
curl -X POST https://{tenantID}.authknox.com/token \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type":    "client_credentials",
    "client_id":     "your-mgmt-app-id",
    "client_secret": "your-mgmt-app-secret",
    "audience":      "https://management.authknox.com"
  }'
Step 2 — call a management endpoint
curl https://{tenantID}.authknox.com/applications \
  -H "Authorization: Bearer eyJhbGci..."

Important: always use the native subdomain

The JWT must be obtained from https://{tenantID}.authknox.com/token, not a custom domain. The management API validates the JWT iss claim against the native subdomain issuer. A token obtained via a custom domain carries a different iss and will be rejected with 401.

Required scopes

Each endpoint requires a specific scope in the bearer token. Request only the scopes your integration needs.

applications:read List or get applications
applications:create Create applications
applications:delete Delete applications
applications:rotate Rotate or invalidate secrets
apis:read List or get API resources
apis:create Register API resources
apis:delete Delete API resources
domains:read Get custom domain status
domains:create Register or confirm DNS for a custom domain
domains:delete Delete a custom domain

Auth errors

Error responses
// 401 — missing or invalid token
{ "error": "unauthorized", "error_description": "missing or malformed Authorization header" }
{ "error": "unauthorized", "error_description": "invalid or expired token" }

// 403 — authenticated but wrong tenant or missing scope
{ "error": "forbidden" }
{ "error": "forbidden", "error_description": "scope \"applications:create\" required" }

Applications

An application represents a machine identity — a service or job that needs to request tokens. Each application has a client_id, a secret (hashed with argon2id), and a set of grants defining which API resources it can request tokens for.

GET

/applications

applications:read

Returns a paginated list of applications. Results are sorted alphabetically by client_id.

Request
curl "https://{tenantID}.authknox.com/applications?page_size=20" \
  -H "Authorization: Bearer $MGMT_TOKEN"
200 OK
{
  "applications": [
    {
      "client_id":  "billing-service",
      "name":       "Billing Service",
      "enabled":    true,
      "created_at": "2024-05-01T10:00:00Z",
      "api_grants": [
        {
          "audience": "https://payments.acme.com",
          "scopes":   ["payments:read", "payments:write"]
        }
      ]
    }
  ],
  "next_page_token": "dGVzdA"
}
Query parameters
page_size optional Number of results per page. Integer 1–100, default 20. Non-integer or out-of-range values return 400.
page_token optional Opaque cursor from a previous response's next_page_token. Absent on first page. next_page_token is omitted (not null) when there are no more results.

GET

/applications/{clientID}

applications:read

Returns a single application. Secrets are never included in GET responses.

Request
curl https://{tenantID}.authknox.com/applications/billing-service \
  -H "Authorization: Bearer $MGMT_TOKEN"
200 OK
{
  "client_id":  "billing-service",
  "name":       "Billing Service",
  "enabled":    true,
  "created_at": "2024-05-01T10:00:00Z",
  "api_grants": [...]
}

POST

/applications

applications:create

Creates an application and returns the client_secret once. Store it immediately — it cannot be retrieved again. The response includes Cache-Control: no-store per RFC 6749 §5.1.

Request
curl -X POST https://{tenantID}.authknox.com/applications \
  -H "Authorization: Bearer $MGMT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "client_id": "billing-service",
    "name":      "Billing Service",
    "api_grants": [
      {
        "audience": "https://payments.acme.com",
        "scopes":   ["payments:read", "payments:write"]
      }
    ]
  }'
201 Created
{
  "client_id":     "billing-service",
  "name":          "Billing Service",
  "enabled":       true,
  "created_at":    "2024-05-01T10:00:00Z",
  "api_grants":    [...],
  "client_secret": "cs_live_..."
}
// Cache-Control: no-store
// Pragma: no-cache
Request body (JSON)
client_id required Unique identifier for this application. Used as the sub claim in issued tokens. Immutable after creation.
name required Human-readable display name.
api_grants optional Array of grants. Each grant has an audience (must be a pre-registered API resource) and a scopes array. Max 10 grants; max 30 scopes per grant; max 48 chars per scope token.

DELETE

/applications/{clientID}

applications:delete

Permanently deletes an application and removes it from the global client index. Tokens already issued remain valid until they expire.

Request
curl -X DELETE \
  https://{tenantID}.authknox.com/applications/billing-service \
  -H "Authorization: Bearer $MGMT_TOKEN"

Returns 204 No Content on success.


POST

/applications/{clientID}/rotate-secret

applications:rotate

Generates a new secret and optionally keeps the old one valid for a transition window. Set previous_secret_ttl_seconds to a non-zero value to allow both secrets to be accepted simultaneously during deployment. Set it to 0 for an immediate hard rotation — the old secret is invalidated at once.

Request — grace period rotation (1 hour)
curl -X POST \
  https://{tenantID}.authknox.com/applications/billing-service/rotate-secret \
  -H "Authorization: Bearer $MGMT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"previous_secret_ttl_seconds": 3600}'
200 OK
{
  "client_id":     "billing-service",
  "client_secret": "cs_live_..."
}
// Cache-Control: no-store
// Pragma: no-cache
Request body (JSON)
previous_secret_ttl_seconds required How long the old secret remains valid after rotation. 0 = immediate invalidation. 1–604800 (7 days) = grace period. Missing or null returns 400.

POST

/applications/{clientID}/invalidate-previous-secret

applications:rotate

Immediately drops all previous (non-current) secrets for an application. Use this after a grace-period rotation once you have confirmed all instances have picked up the new secret and the transition window can be closed early.

Request
curl -X POST \
  https://{tenantID}.authknox.com/applications/billing-service/invalidate-previous-secret \
  -H "Authorization: Bearer $MGMT_TOKEN"

Returns 204 No Content on success. Safe to call even if no previous secret exists.

API Resources

An API resource is an audience value that applications can request tokens for. Register a resource server here before granting access to it in any application. The audience field becomes the aud claim in issued tokens.

GET

/apis

apis:read

Returns a paginated list of registered API resources. Supports the same page_size and page_token parameters as the applications list.

Request
curl https://{tenantID}.authknox.com/apis \
  -H "Authorization: Bearer $MGMT_TOKEN"
200 OK
{
  "apis": [
    {
      "audience":   "https://payments.acme.com",
      "name":       "Payments API",
      "scopes":     ["payments:read", "payments:write"],
      "enabled":    true,
      "created_at": "2024-05-01T10:00:00Z"
    }
  ],
  "next_page_token": "dGVzdA"
}

GET

/apis/{audience}

apis:read

Returns a single API resource by audience value. The audience must be URL-encoded in the path.

Request
curl "https://{tenantID}.authknox.com/apis/https%3A%2F%2Fpayments.acme.com" \
  -H "Authorization: Bearer $MGMT_TOKEN"

POST

/apis

apis:create

Registers a new API resource. The audience must be unique within your tenant. Define all scopes this resource supports — applications can only request scopes listed here.

Request
curl -X POST https://{tenantID}.authknox.com/apis \
  -H "Authorization: Bearer $MGMT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "audience": "https://payments.acme.com",
    "name":     "Payments API",
    "scopes":   ["payments:read", "payments:write", "payments:refund"]
  }'
201 Created
{
  "audience":   "https://payments.acme.com",
  "name":       "Payments API",
  "scopes":     ["payments:read", "payments:write", "payments:refund"],
  "enabled":    true,
  "created_at": "2024-05-01T10:00:00Z"
}
Request body (JSON)
audience required The audience string for this resource server. A URI is conventional (https://api.yourdomain.com) but any unique string works. Becomes the aud claim in tokens.
name required Human-readable name for this resource server.
scopes optional Array of scope strings this resource server accepts. Max 30 scopes; each scope token max 48 characters. Applications can only request scopes defined here.

DELETE

/apis/{audience}

apis:delete

Deletes an API resource. The audience must be URL-encoded in the path. Existing application grants referencing this audience are not automatically cleaned up.

Request
curl -X DELETE \
  "https://{tenantID}.authknox.com/apis/https%3A%2F%2Fpayments.acme.com" \
  -H "Authorization: Bearer $MGMT_TOKEN"

Returns 204 No Content on success.

Custom Domain

By default your token endpoint lives at {tenantID}.authknox.com/token. A custom domain lets your services call auth.yourdomain.com/token instead. TLS is provisioned automatically via Google Certificate Manager. Custom domains are available on paid plans only.

Domain status flow

pending_initiation awaiting_dns cert_pending active

After you call POST /domain, the provisioner picks up the request within 5 minutes and creates the DNS challenge. You then add two CNAME records to your DNS provider and call POST /domain/confirm-dns. Certificate provisioning runs automatically. If provisioning fails, the status moves to failed — delete the domain and register again to retry.

POST

/domain

domains:create

Registers a custom domain. The provisioner creates the DNS auth challenge within 5 minutes. Poll GET /domain until status is awaiting_dns, then add the returned DNS records and call POST /domain/confirm-dns. Rate limited to 3 registrations per tenant per 24 hours.

Request
curl -X POST https://{tenantID}.authknox.com/domain \
  -H "Authorization: Bearer $MGMT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"domain": "auth.yourdomain.com"}'
202 Accepted
{
  "domain":  "auth.yourdomain.com",
  "status":  "pending_initiation",
  "dns_records": [
    {
      "type":  "CNAME",
      "name":  "auth.yourdomain.com",
      "value": "{tenantID}.authknox.com.",
      "ttl":   300
    }
  ]
}

The routing CNAME is always returned. The challenge CNAME appears once status reaches awaiting_dns.


GET

/domain

domains:read

Returns the current custom domain status. When status is awaiting_dns, both DNS records are included: the routing CNAME and the certificate challenge CNAME. Add both to your DNS provider before confirming.

Request
curl https://{tenantID}.authknox.com/domain \
  -H "Authorization: Bearer $MGMT_TOKEN"
200 OK — awaiting_dns
{
  "domain":  "auth.yourdomain.com",
  "status":  "awaiting_dns",
  "dns_records": [
    {
      "type":  "CNAME",
      "name":  "auth.yourdomain.com",
      "value": "{tenantID}.authknox.com.",
      "ttl":   300
    },
    {
      "type":  "CNAME",
      "name":  "_acme-challenge.auth.yourdomain.com",
      "value": "abc123.authorize.certificatemanager.goog.",
      "ttl":   3600
    }
  ]
}
Status values
pending_initiation Queued for provisioning. The provisioner will create the DNS challenge within 5 minutes.
awaiting_dns DNS challenge is ready. Add both CNAME records to your DNS provider, then call POST /domain/confirm-dns.
cert_pending DNS confirmed. Certificate provisioning is in progress. This can take 5–30 minutes depending on DNS propagation.
active Your custom domain is live. HTTPS traffic to it is served by AuthKnox.
failed Provisioning failed permanently. Delete the domain and register again to retry.

POST

/domain/confirm-dns

domains:create

Tells AuthKnox you have added the DNS records and certificate provisioning can proceed. The domain must be in awaiting_dns status. Returns 409 if called in any other state.

Request
curl -X POST https://{tenantID}.authknox.com/domain/confirm-dns \
  -H "Authorization: Bearer $MGMT_TOKEN"
200 OK
{
  "domain": "auth.yourdomain.com",
  "status": "cert_pending",
  "dns_records": [
    {
      "type":  "CNAME",
      "name":  "auth.yourdomain.com",
      "value": "{tenantID}.authknox.com.",
      "ttl":   300
    }
  ]
}

DELETE

/domain

domains:delete

Removes the custom domain. Routing stops immediately — the domain stops resolving to AuthKnox as soon as this call returns. Certificate Manager resources are cleaned up asynchronously by the provisioner. Can be called in any state.

Request
curl -X DELETE https://{tenantID}.authknox.com/domain \
  -H "Authorization: Bearer $MGMT_TOKEN"

Returns 204 No Content on success.

Common errors

All errors follow a consistent shape.

Error shape
{ "error": "error_code", "error_description": "human-readable detail" }
HTTP status codes
400 Malformed request body, missing required field, or out-of-range parameter (e.g. page_size not integer, previous_secret_ttl_seconds missing).
401 Missing, malformed, or expired JWT. Check that the token was obtained from the native subdomain token endpoint.
403 Authenticated but not authorised: wrong tenant, missing scope, or plan limit reached.
404 Resource not found.
409 Conflict: resource already exists, or state transition not allowed (e.g. confirm-dns when not awaiting_dns).
413 Request body too large. Management endpoints accept up to 18 KB.
429 Rate limit exceeded. Returned for domain registration when the 3/24h limit is reached. Response includes retry_after_seconds.

Ready to build?

Free to start. No credit card required. Your first 10,000 tokens are on us.

Token docs →