API and command line
Almost everything the web desktop does goes through one route, and scripts can use it too. (Downloading and uploading files, previews, the log export, the diagnostic bundle, the Terminal and the virtual machines' screens have addresses of their own.)
POST https://<server>:5001/api/call/<operation>
Authorization: Bearer osm_<id>_<secret>
Content-Type: application/json
{the operation's arguments}
The answer is the operation's result as JSON (HTTP 200), or {"error": "..."} with the status the operation gives (400 a wrong argument, 401 no or a bad token, 403 not allowed, 404 nothing there, 409 not now, 429 an address paused after failed attempts). An operation that takes a while starts a job and answers {"job": "<id>"}: follow it with jobs.get ({"id": "<id>"}) until its state is no longer running.
Tokens
My Account > API tokens > New token... makes one. It is shown once; the server keeps only its SHA-256. Each token has:
- an account: a request with it is that account's, with the account's role as it is at that moment (an Administrator who is no longer one is a Standard user), and only while the account may sign in: the tokens of a locked or expired account stop working. A renamed account keeps its tokens;
- a scope (It may): Read only (nothing changes) runs only the operations that change nothing; Everything this account may do;
- an expiry (It works for): 30 days, 90 days, a year, or until it is deleted;
- OSM Connect (It may also be used through OSM Connect, on servers that have it): off by default. A token works through the server's OSM Connect address only when it was made with this ticked and an Administrator allows API tokens there (Settings > OSM Connect); even then, the changes OSM Connect guards (deleting data, accounts and passwords, security, network and update settings...) stay with a person signed in at the desktop.
Never with a token, whatever its scope: signing in and out, the account's own password and email address, two-step sign-in, passkeys and trusted browsers, the tokens themselves, the list of sign-ins and ending them, the Terminal, the settings of the server's own screen, and opening apps (their tickets and passwords). Nor any operation whose answer is a password: the apps' own passwords, a virtual machine's account, the domain Administrator's. Those stay with a person at the desktop, and the reference marks them not with a token.
A wrong token counts as a failed sign-in for its address, which is paused like after wrong passwords. Tokens need no CSRF token: they are not cookies, and a browser on another site cannot send the header.
Logs, source Administrator actions, names the token of each change. It never writes a password or another secret: the arguments that can hold one (keys, scripts, an app's environment) are hidden, a long text is written as its length, and a password in an address is hidden.
A token reads settings, not the secrets in them: in what an operation that changes nothing answers a token, every field named like a secret (a password or passphrase, a client secret, a private key, a token), a scheduled task's script, and a container project's compose file and variables (docker.project_get: they hold its passwords) read ***. A container's environment (docker.inspect) shows no password either, for anyone: a variable named like one, a password in an address (user:password@), and the passwords OSM made for an app read ***. A secret an operation makes is still shown, once, as it is made.
The reference
My Account > API tokens > Reference... lists every operation of the server, read from its own code: its name, who may run it, whether it changes anything, whether a token may run it, its text, and the arguments it reads (their types and choices). So it is always the reference of the version installed. osm-cli.py ops [WORD] prints it:
pool.create(disks, kind, redundancy?, level?, volume?{fs, size_gb?}) [admin, changes]
A new pool, and a first volume in it if asked ({'size_gb': 0 (all) or GB, 'fs'}).
name: every call needs it.name?: it may be left out (it has a default, or only what is given changes).name*: some calls need it, depending on the others. The text says which (for examplevm.create'sinstaller, fortemplate: "osm"only).name{...}: an object, and its own fields (or, for a list, each item's).
apitokens.reference (or osm-cli.py --json ops [WORD]) answers the same as JSON, with each argument's limits and default too: per argument name, type, required, sometimes (when some calls need it), and default, choices, lo, hi, maxlen, pattern and fields when it has them.
osm-cli.py
A single Python file (3.8 or newer, nothing else), from the server itself: https://<server>:5001/osm-cli.py.
export OSM_SERVER=https://nas.local:5001 OSM_TOKEN=osm_...
osm-cli.py trust # shows the server's certificate, then pins it if you say yes
osm-cli.py status
osm-cli.py ops snapshot
osm-cli.py call snap.take '{"share": "Photos"}'
osm-cli.py call updates.install # follows the job until it ends (--no-wait: does not)
It sends the token only to the certificate pinned by trust (a self-signed certificate has nothing else to vouch for it), or, with nothing pinned, to a certificate the computer trusts (Let's Encrypt). Another certificate at the same address: it stops before sending anything. Before you accept a certificate with trust, compare the fingerprint it shows with the one in Settings > Security > Certificate.
Where trust cannot ask (a script, no terminal), it pins nothing unless you say which certificate: osm-cli.py trust --fingerprint AB:CD:..., with the SHA-256 fingerprint copied from Settings > Security > Certificate (it is pinned only if the server shows that one), or --yes to pin the certificate shown without comparing.
On the server itself, root has osm (sudo osm ...), which talks to the agent's socket directly and needs no token.
Example: a snapshot from a script
curl --cacert server.crt -s -X POST \
-H "Authorization: Bearer $OSM_TOKEN" -H 'Content-Type: application/json' \
-d '{"share": "Photos"}' https://nas.local:5001/api/call/snap.take
(server.crt: the server's certificate, saved from the browser's padlock. Compare its SHA-256 fingerprint with the one in Settings > Security > Certificate.)