Skip to content

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_type is DPoP for signing-scope device flows.
  • token_type is Bearer for 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 sshteam CLI 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 (Bearer vs DPoP). Mixing those headers causes hard-to-read failures that look like generic auth errors.