Skip to main content
API clients are confidential OAuth 2.0 clients that use the client credentials grant to automate the Maverics platform via its public APIs. API clients are passwordless. Authentication is done via JWT client assertions signed with a private key.

Prerequisites

  • Organization owner role — Required to create, edit, or revoke API clients and their key pairs.
  • HTTPS client — e.g., curl or any HTTP library.

Create an API Client

1

Open the API Clients section

Click your profile in the upper-right corner of the Console, then click Organizations. Select the organization you want to manage. Locate the API Clients section on the organization page.
2

Create the client

Click Create. Enter a Name (required) and an optional Description (e.g., “CI deploy bot”). Click Create to save.
3

Add a key pair

With the API client settings open, click Add Key Pair. The Console generates a key pair on the server, displays the fingerprint, and prompts you to download the private key as a PEM file.
4

Download and store the private key

Click Download Private Key, then click Done to close the modal. Store the file securely — treat it like any other production secret.
The private key is delivered to your browser only at creation time and is not stored by Strata. If the file is lost, revoke the key pair and add a new one.
You can attach multiple key pairs to a single client to support rotation. Revoke an individual key pair from the API client settings without affecting others.

Obtain an Access Token

API clients authenticate to the token endpoint using the OAuth 2.0 client credentials grant (RFC 6749 §4.4) with a JWT client assertion (RFC 7523). The assertion proves possession of the client’s private key without transmitting it.

Discover the Token Endpoint

The auth endpoint is region-specific. Discover it from the OpenID Connect discovery document for your environment:
EnvironmentDiscovery document
UShttps://auth.us-east-2.strata.io/.well-known/openid-configuration
UKhttps://auth.eu-west-2.strata.io/.well-known/openid-configuration
Read the token_endpoint field from the discovery response and use its value as the destination for all token requests. Always take the endpoint from discovery rather than hardcoding the path, as it is the authoritative source.

Build the Client Assertion

Construct a JWT signed with your client’s private key using the ES256 algorithm. JWS header:
FieldValue
algES256
typJWT
JWT claims:
ClaimDescription
issYour API client ID (e.g., client_<uuid>).
subYour API client ID. Must equal iss.
audThe token endpoint URL from discovery.
expExpiry timestamp (seconds since epoch). Must be in the future.
Inspect an example assertion on jwt.io with the placeholder header and claims pre-populated.

Send the Token Request

POST the assertion to the token endpoint with form-encoded parameters:
curl -X POST https://auth.<region>.strata.io/oauth2/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials" \
  -d "client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer" \
  -d "client_assertion=<signed JWT>"
A successful response returns an opaque bearer token:
{
  "access_token": "eyJhbGciOi...",
  "token_type": "Bearer",
  "expires_in": 3600
}
Include the token in the Authorization header for subsequent API calls:
Authorization: Bearer <access_token>

Example code

Each tab builds a client assertion and exchanges it for an access token. Replace the placeholders with your client ID, private key path, and token endpoint.
// Run:
//   go get github.com/go-jose/go-jose/v4
//   CLIENT_ID=<your-client-id> \
//     KEY_PATH=client.pem \
//     TOKEN_URL=https://auth.<region>.strata.io/oauth2/token \
//     go run main.go
package main

import (
	"crypto/ecdsa"
	"crypto/x509"
	"encoding/pem"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"os"
	"strings"
	"time"

	"github.com/go-jose/go-jose/v4"
	josejwt "github.com/go-jose/go-jose/v4/jwt"
)

func main() {
	clientID := os.Getenv("CLIENT_ID")
	keyPath := os.Getenv("KEY_PATH")
	tokenURL := os.Getenv("TOKEN_URL")

	pemBytes, _ := os.ReadFile(keyPath)
	block, _ := pem.Decode(pemBytes)
	raw, _ := x509.ParsePKCS8PrivateKey(block.Bytes)
	key := raw.(*ecdsa.PrivateKey)

	signer, _ := jose.NewSigner(
		jose.SigningKey{Algorithm: jose.ES256, Key: key},
		(&jose.SignerOptions{}).WithType("JWT"),
	)

	now := time.Now()
	claims := josejwt.Claims{
		Issuer:   clientID,
		Subject:  clientID,
		Audience: josejwt.Audience{tokenURL},
		IssuedAt: josejwt.NewNumericDate(now),
		Expiry:   josejwt.NewNumericDate(now.Add(5 * time.Minute)),
	}

	assertion, _ := josejwt.Signed(signer).Claims(claims).Serialize()

	form := url.Values{
		"grant_type":            {"client_credentials"},
		"client_assertion_type": {"urn:ietf:params:oauth:client-assertion-type:jwt-bearer"},
		"client_assertion":      {assertion},
	}

	resp, _ := http.Post(tokenURL, "application/x-www-form-urlencoded", strings.NewReader(form.Encode()))
	defer resp.Body.Close()

	// The response body contains the access token (JSON: access_token, token_type, expires_in).
	body, _ := io.ReadAll(resp.Body)
	fmt.Println("status:", resp.Status)
	fmt.Println(string(body))
}

Common Errors

StatusErrorLikely Cause
400invalid_clientinvalid clientThe sub claim does not match a registered API client in the requested region.
400invalid_clientinvalid JWT signatureThe signature does not verify against any registered public key for this client. Confirm you are signing with the matching private key.
400invalid_clientfailed to parse JWTThe assertion is malformed. Verify it is a compact-serialized JWS with three base64url-encoded segments.
400invalid_requestMissing or malformed form parameter. Confirm grant_type, client_assertion_type, and client_assertion are all present and well-formed.

Rotate or Revoke

  • Rotate — Add a new key pair while the existing one is still active, switch your client to the new private key, then revoke the old key pair.
  • Revoke a key pair — Open the client drawer and click the revoke icon next to the key pair. Tokens issued before revocation remain valid until they expire.
  • Delete the client — Removes the client and all of its key pairs. The platform will begin rejecting new token requests for the deleted client.
  • User Management — Organization roles required to administer API clients.
  • Audit Logs — API client lifecycle events appear in the audit log.