SDKsAuthentication

Authentication

Every SDK request must be authenticated using exactly one of two methods: an API token or a node ID.

API tokens

The simplest way to authenticate. Generate a token from the CLI or the CiderStack app, then pass it directly to the client.

Tokens are prefixed with csk_ and come in two permission levels:

PermissionCan readCan write (start/stop/create/delete)
readOnlyYesNo
fullAccessYesYes

Read-only tokens can list VMs, get node stats, view snapshots and templates — but cannot start, stop, create, or delete anything.

How to get a token

  1. CiderStack CLI: cider fleet token generate --name "my-script"
  2. CiderStack app: Settings > Fleet > API Tokens
  3. Programmatically: via the SDK (requires node ID auth — see below)

Using a token

// JavaScript
import { FleetClient } from "@ciderstack/fleet-sdk";
 
const client = new FleetClient({
  host: "192.168.1.100",
  apiToken: "csk_abc123...",
});
# Python
from ciderstack import FleetClient
 
client = FleetClient("192.168.1.100", api_token="csk_abc123...")

Node ID via pairing

For advanced use cases — or when you need to generate API tokens programmatically — you can pair the SDK with a Fleet node using a 6-digit code displayed in the CiderStack app UI.

The pairing process generates a P-256 (SECP256R1) ECDSA keypair and registers your SDK client as a trusted node in the fleet.

JavaScript

import { FleetClient } from "@ciderstack/fleet-sdk";
 
// One-time pairing
const creds = await FleetClient.pair(
  "192.168.1.100",  // Fleet node host
  "123456",         // 6-digit code from UI
  "my-ci-script",   // Display name (optional)
  9473,             // Port (optional, default 9473)
);
 
// creds contains:
// {
//   nodeId: string,           — your unique node ID (save this)
//   privateKeyHex: string,    — P-256 private key (hex)
//   publicKeyHex: string,     — P-256 public key (hex)
//   responderNodeId: string,  — Fleet node's ID
//   responderName: string,    — Fleet node's display name
// }
 
// Use the node ID for future connections
const client = new FleetClient({
  host: "192.168.1.100",
  nodeId: creds.nodeId,
});

Python

from ciderstack import FleetClient
 
# One-time pairing (requires cryptography package)
creds = FleetClient.pair(
    "192.168.1.100",  # Fleet node host
    "123456",         # 6-digit code from UI
    "my-ci-script",   # Display name (optional)
    9473,             # Port (optional, default 9473)
)
 
# creds is a dict:
# {
#   "node_id": str,            — your unique node ID (save this)
#   "private_key_hex": str,    — P-256 private key (hex)
#   "public_key_hex": str,     — P-256 public key (hex)
#   "responder_node_id": str,  — Fleet node's ID
#   "responder_name": str,     — Fleet node's display name
# }
 
# Use the node ID for future connections
client = FleetClient("192.168.1.100", node_id=creds["node_id"])

Note: Python pairing requires the cryptography package. Install it with pip install ciderstack[pairing].


Generating tokens programmatically

Once paired via node ID, you can generate API tokens for simpler future authentication:

// JavaScript
const client = new FleetClient({ host: "192.168.1.100", nodeId: creds.nodeId });
 
const token = await client.generateAPIToken("ci-pipeline", "fullAccess");
console.log(token.token);  // "csk_..." — save securely
console.log(token.id);     // UUID for revoking later
 
// Now use the token directly
const tokenClient = new FleetClient({
  host: "192.168.1.100",
  apiToken: token.token,
});
# Python
client = FleetClient("192.168.1.100", node_id=creds["node_id"])
 
token = client.generate_api_token("ci-pipeline", "fullAccess")
print(token.token)  # "csk_..." — save securely
print(token.id)     # UUID for revoking later
 
# Now use the token directly
token_client = FleetClient("192.168.1.100", api_token=token.token)

Important: The full token string is only returned once at creation time. Store it securely. Token generation also requires node ID authentication — you cannot use an API token to create more tokens.


Managing tokens

// JavaScript — list all tokens (strings are redacted)
const tokens = await client.listAPITokens();
for (const t of tokens) {
  console.log(`${t.name}: ${t.tokenPrefix}... (${t.permissions})`);
}
 
// Revoke a token
await client.revokeAPIToken(token.id);
# Python — list all tokens (strings are redacted)
tokens = client.list_api_tokens()
for t in tokens:
    print(f"{t.name}: {t.token_prefix}... ({t.permissions})")
 
# Revoke a token
client.revoke_api_token(token.id)

See also