Get a token
Exchange the credential for a short-lived (1 hour) bearer token at the token endpoint,https://conduit.example.com/oauth/token (your instance’s exact URL is
shown in the client’s Manage credentials dialog). Conduit publishes it, with
the rest of its OAuth configuration, in the standard
authorization server metadata
document at https://conduit.example.com/.well-known/oauth-authorization-server:
token_endpoint, the client authentication methods it accepts
(token_endpoint_auth_methods_supported — for API clients, client_secret_basic
and private_key_jwt; none is for MCP clients), and the algorithms it accepts
for a signed assertion (token_endpoint_auth_signing_alg_values_supported:
RS256, ES256). OAuth
client libraries that support discovery read it given just the instance’s base
URL, the document’s issuer.
private_key_jwt is the same grant with a signed client assertion
(client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer),
which is the stronger option because no shared secret is transmitted. Standard
OAuth client libraries implement both and refresh the token for you.
Requesting scope down-selects from what the client was granted; omit it to get
all granted scopes. The response is a standard OAuth token:
Private-key JWT authentication
private_key_jwt (RFC 7523) is the recommended credential for unattended use.
Instead of sending a shared secret, your client signs a short-lived JWT
assertion with a private key that never leaves your infrastructure. You register
only the matching public key with Conduit, so no reusable secret is ever
transmitted to the token endpoint or stored in Conduit’s database — a leaked
request log or a database dump can’t be replayed to mint tokens. A client secret,
by contrast, is a bearer value: anyone who reads it once can use it until you
rotate it. Prefer private_key_jwt for CI and production.
Generate a key pair
Conduit accepts an RSA (≥ 2048-bit) or EC P-256 public key, as a PEM or a JWK. PEM is the simplest — twoopenssl commands, nothing else to install:
pub.pem (the -----BEGIN PUBLIC KEY----- block) into
Settings → API Clients → Add credential → Public key. Conduit derives a
kid for it (the RFC 7638 thumbprint) and shows it next to the credential.
Already have a JWK? Paste that instead — the same field takes either form.
Request a token
Standard OAuth libraries build and sign the assertion for you. The raw exchange is the same client-credentials grant, with a signed assertion in place of Basic auth — the assertion’siss and sub are the client ID (copy it from the
API clients table or the client’s Manage credentials dialog), aud is the
token endpoint URL (shown in the same dialog), and exp is a few minutes out with a unique jti:
aud must exactly match your instance — either its base URL or that URL
plus /oauth/token (the metadata document’s token_endpoint). This binds the
assertion to one instance so it can’t be replayed against another, and a
mismatch is the most common setup error: the token endpoint returns
invalid_client (deliberately without saying why). Set aud to the token
endpoint you’re POSTing to and they always agree.
Revoking access
- Disable or delete a client, or revoke a single credential, in Settings → API Clients — it takes effect on the next request. Revoking one credential leaves the client’s other credentials working, so it is the clean way to retire a leaked secret mid-rotation.
CONDUIT_DISABLE_API_CLIENTS=true and restart Conduit to refuse token minting
and reject every existing API-client token instance-wide (break-glass for a
suspected compromise).
Machine actions are attributed to api-client:<name>, and every audit detail
includes the immutable client ID plus the credential ID that minted the token.
Known-client authentication failures are included in the workspace’s
audit:read export, coalesced to one row per client/source-IP/minute; repeats
and unknown client IDs remain available through telemetry without amplifying
audit-log writes.
Each audit entry also carries actor_user_id (the acting user’s id, or the
API client’s backing service user), trace_id and span_id. Telemetry
identifies people by user.id, never by email, so these are how a SIEM joins
an event from your telemetry backend to the audit entry, and its email,
behind it. See What telemetry contains.