13 API Reference Appendices
This appendix summarizes key API contracts used by browser, CLI, and join workflows.
Use this appendix when you need endpoint-level details during automation, troubleshooting, or integration work.
If you need term definitions first, open 14-glossary.md.
Guide-first navigation:
- For operational join steps, use
04-joining-servers.md. - For device registration workflow, use
07-registering-devices.md. - For signing workflows, use
08-issuing-certificates.md.
13.1 API Surface Map
graph LR
A[CLI and Join Scripts] --> B[OAuth Device Authorization]
B --> C[Token Endpoint with DPoP]
C --> D[Join API or Signing API]
D --> E[Policy Evaluation and CA Signing]
F[Web UI] --> G[Session Auth and Admin APIs]
Authentication model by surface:
- Browser UI: session-based login and role-guarded routes.
- CLI and join scripts: OAuth device authorization with DPoP-bound tokens.
- Signing/join operations: token scope and request proof validation are both required.
13.2 Device Authorization Endpoints
These endpoints power CLI and script authorization flows.
POST /oauth2/device_authorization
Purpose:
- Start device authorization and return verification metadata.
Request parameters (application/x-www-form-urlencoded):
| Parameter | Required | Type | Description |
|---|---|---|---|
client_id |
Yes | string | OAuth client identifier (for example sshteam-cli). |
scope |
No | string | Requested scope: signing or join. Defaults to join when omitted. |
device_name |
No | string | Optional display name persisted for signing-scope device records. |
Example success output (200):
{
"device_code": "dvc_2f9f6f3d7f224d3d9b9e",
"user_code": "ABCD-EFGH",
"verification_uri": "https://<hostname>/device/verify",
"verification_uri_complete": "https://<hostname>/device/verify?user_code=ABCD-EFGH&device_code=dvc_2f9f6f3d7f224d3d9b9e",
"expires_in": 600,
"interval": 5
}
POST /oauth2/token
Purpose:
- Exchange approved device code for tokens or refresh tokens.
Request parameters (application/x-www-form-urlencoded):
| Parameter | Required | Type | Description |
|---|---|---|---|
grant_type |
Yes | string | Device flow: urn:ietf:params:oauth:grant-type:device_code, refresh flow: refresh_token. |
device_code |
Conditional | string | Required when grant_type is device code. |
refresh_token |
Conditional | string | Required when grant_type is refresh token. |
client_id |
Conditional | string | Required for device-code exchange; not used by refresh-token exchange. |
DPoP (header) |
Conditional | string | Required for signing scope token exchange and refresh grant handling. |
Example success output (200):
{
"access_token": "eyJ...",
"refresh_token": "eyJ...",
"token_type": "DPoP or Bearer",
"expires_in": 86400,
"scope": "signing or join"
}
Response behavior note:
token_typeisDPoPfor signing-scope device flows.token_typeisBearerfor join-scope flows.
Example pending output (400):
{
"error": "authorization_pending",
"error_description": "Authorization request is still pending"
}
13.3 Join and Signing Endpoints
POST /api/v1/ssh/join
Purpose:
- Register a server and return trust material used for SSH CA validation.
Headers:
| Header | Required | Description |
|---|---|---|
Authorization |
Yes | Bearer <access-token> with join scope. |
Content-Type |
Yes | application/json. |
Request body fields (representative):
| Field | Required | Type | Description |
|---|---|---|---|
hostname |
Yes | string | Target server hostname or address. |
port |
No | number | SSH service port, defaults to 22 if omitted by client workflow. |
osFamily |
Yes | string | Target OS family captured during join (for example linux, windows). |
osVersion |
Yes | string | Target OS version string. |
sshFingerprints |
No | array |
Host-key fingerprints collected from target server. |
name |
No | string | Friendly name shown in administration UI. |
tags |
No | array |
Tags used for policy targeting. |
timezone |
No | string | Optional server timezone. |
serverId |
No | string | Existing server ID for update-path joins. |
Example success output (200, text/plain):
# TrustedUserCAKeys
ssh-rsa AAAA...
ssh-ed25519 AAAA...
# sshteam-server-id: srv_a18c0c2e
POST /api/v1/ssh/sign
Purpose:
- Submit certificate signing request from CLI flows (
sign,issue,agent).
Headers:
| Header | Required | Description |
|---|---|---|
Authorization |
Yes | DPoP <access-token> with signing scope. |
DPoP |
Yes | Proof JWT bound to token and request URL/method. |
Content-Type |
Yes | application/json. |
Request body fields:
| Field | Required | Type | Description |
|---|---|---|---|
principal |
Yes | string | UNIX account requested in certificate. |
server_fingerprint |
Yes | string | Target server host-key fingerprint. |
public_key |
Yes | string | OpenSSH-formatted public key. |
certificate_type |
No | string | ED25519 or RSA; defaults to ED25519 when omitted/blank. |
timezone |
No | string | IANA timezone override for policy window evaluation. |
Example success output (200):
{
"certificate": "ssh-ed25519-cert-v01@openssh.com AAAA..."
}
Example deny output (403):
{
"error": "No certificate policy permits this request"
}
GET /api/v1/devices
Purpose:
- List registered devices for current user context.
Headers:
| Header | Required | Description |
|---|---|---|
| Session cookie | Yes | Authenticated browser session for current user. |
Example success output (200):
[
{
"id": "dev_77f7a",
"displayName": "macbook-pro",
"createdAt": "2026-07-15T21:03:11Z",
"lastSeenAt": "2026-07-16T05:44:42Z",
"revoked": false
}
]
DELETE /api/v1/devices/{deviceId}
Purpose:
- Revoke an existing device registration.
Behavior:
- Revocation is immediate.
- Repeated revoke requests are treated idempotently.
Path and headers:
| Name | Required | Type | Description |
|---|---|---|---|
deviceId (path) |
Yes | string | Device identifier returned by device list endpoint. |
| Session cookie | Yes | string | Authenticated browser session for current user. |
Example success output (204, no response body).
13.4 Error Codes and Expected HTTP Statuses
Use this section as an operator baseline. Exact payload fields may vary by endpoint.
| Scenario | Typical HTTP status | Notes |
|---|---|---|
| Successful device authorization start | 200 | Returns device/user codes and verification URI |
| Device polling pending approval | 400 | OAuth error body commonly indicates authorization_pending |
| Device polling denied | 400 | OAuth error body commonly indicates access_denied |
| Device code expired | 400 | OAuth error body commonly indicates expired_token |
| Missing or invalid session for protected UI route | 302 or 401/403 | Redirect to /login or auth failure depending on route/surface |
| Invalid token or DPoP proof on protected API | 401 | Token invalid, expired, revoked, or proof mismatch |
| Authenticated but not authorized for action | 403 | Role or policy boundary denies action |
| Policy denial on sign request | 403 | Request valid but does not match allow policy |
| Resource conflict on optimistic lock update | 409 | Typical for concurrent policy updates |
| Validation error in request payload | 400 | Field format, required fields, or logical constraints fail |
Operational guidance:
- Treat 401 as authentication/proof problem.
- Treat 403 as permission/policy boundary problem.
- Treat 409 as concurrency/version conflict.
13.5 Example Payloads and Curl Snippets
The snippets below are reference examples for documentation and controlled testing.
Start device authorization:
curl -sS -X POST "https://<hostname>/oauth2/device_authorization" \
-H "Content-Type: application/x-www-form-urlencoded" \
--data "client_id=sshteam-cli&scope=signing"
Poll token endpoint (device flow example):
curl -sS -X POST "https://<hostname>/oauth2/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
--data "grant_type=urn:ietf:params:oauth:grant-type:device_code&device_code=<device_code>&client_id=sshteam-cli"
Sign request with DPoP headers (illustrative):
curl -sS -X POST "https://<hostname>/api/v1/ssh/sign" \
-H "Authorization: DPoP <access_token>" \
-H "DPoP: <proof_jwt>" \
-H "Content-Type: application/json" \
-d '{
"principal": "devops",
"server_fingerprint": "SHA256:example",
"public_key": "ssh-ed25519 AAAA...",
"certificate_type": "ED25519"
}'
Revoke device:
curl -sS -X DELETE "https://<hostname>/api/v1/devices/<deviceId>" \
-H "Cookie: JSESSIONID=<session_id>"
Documentation note:
- Treat these examples as contract guidance; align field names and optional attributes with your deployed version before automation.
13.6 Pro Tip and Common Gotcha
Pro tip:
- For day-to-day operations, run
sshteamCLI commands first and use these API calls only when you need deeper diagnostics or custom integration behavior.
Common gotcha:
- Join and signing endpoints use different auth models (
BearervsDPoP). Mixing those headers causes hard-to-read failures that look like generic auth errors.