Server Keys and Machine Access
How a script, dashboard or integration authenticates to Flow Server without a person signing in — and how long its token lasts.
A person signs in to Infohub and gets a session. A script does not. When something unattended needs to read from Flow Server — a nightly export, an Ignition dashboard, another Infohub instance — it authenticates with a server key instead.
This is the supported alternative to embedding somebody's password in a scheduled task, which is the arrangement it exists to replace.
What a server key is#
A server key is a principal in its own right, created in Flow Config, separate from the user accounts people sign in with. Flow Server recognises two kinds of caller and several endpoints accept either:
| Policy | Accepts |
|---|---|
Username |
An authenticated user only |
ServerKey |
A server key only — host-to-host calls |
UsernameOrServerKey |
Either |
Which policy each endpoint requires is listed in the Flow Server API Reference. An endpoint marked ServerKey cannot be called with a user token no matter how privileged that user is, and the reverse is equally true — this is a distinction of kind, not of rank.
Creating one#
Server keys are created in Flow Config. The key carries a description and its own credentials, so give the description a name that says which system uses it — nightly-csv-export, ignition-line3 — because that description is all you will have to go on when you later need to work out what breaks if you revoke it.
Treat the credentials the way you would any service account secret. Anyone holding them has the access the key has, for as long as the token they minted with it lasts, which can be a very long time.
Getting a token#
Tokens are minted from the server key endpoint:
GET <server-url>api/Token/serverKey
GET <server-url>api/Token/serverKey?expires=2027-01-01T00:00:00Z
The call itself must be authenticated. It returns the token and the expiry Infohub actually granted:
{ "token": "<jwt>", "expires": "2027-01-01T00:00:00Z" }
Use it as a bearer token on subsequent calls:
Authorization: Bearer <jwt>
How the expiry is decided#
Three rules, and the middle one surprises people:
- The maximum lifetime is ten years, and that is also the default when you do not ask for one. Omitting
expiresdoes not give you a short-lived token; it gives you the longest one Infohub will issue. - A longer request is clamped, not refused. Ask for twenty years and you get ten, with a
200and the real expiry in the response. Always readexpiresfrom the response rather than assuming you got what you asked for. - An expiry in the past is rejected with
400and a message naming both the value received and the server's current time — which makes it a useful clock-skew check in itself.
expires is interpreted as UTC. A timestamp sent without a zone is treated as UTC, not as the server's local time. Send an explicit Z (2027-01-01T00:00:00Z) and there is nothing to get wrong; send a bare local time and a token can expire hours earlier or later than you intended.
Ten-year tokens are the default, so decide the lifetime deliberately. A token minted with no expires is valid for a decade and survives the deletion of nothing but the key itself. Set an expiry that matches how long the integration is actually meant to live, and record which system holds which key.
Checking a token#
GET <server-url>api/Token/validate
Returns successfully when the caller presents either a valid user token or a valid server key token, and rejects the call when it is neither. This is the first thing to run when an integration starts failing — it separates "the token is wrong" from "the endpoint is wrong", which otherwise look identical from the client end.
Practices that keep this manageable#
- One key per consuming system. Shared keys cannot be revoked without an outage you cannot scope.
- Record the key against the system in your own asset register. Infohub stores the description; it does not know what depends on the key.
- Prefer a real expiry over the default. A token that expires on a known date fails predictably; a ten-year token fails in a decade, to somebody else.
- Terminate TLS properly. A bearer token is a password in a header — see HTTPS and Certificates.
- Keep Flow Server inside your network. Server keys authenticate a caller; they are not a substitute for a perimeter.
Diagnosing#
| Symptom | Likely cause |
|---|---|
401 on every call |
No Authorization: Bearer header, or the token came from a different instance |
403 on one endpoint, 200 on others |
That endpoint requires the ServerKey policy and you are using a user token, or the reverse |
400 from api/Token/serverKey |
expires is in the past — compare the two timestamps in the message to check for clock skew |
| Token expired far sooner than expected | expires was sent without a zone and read as UTC |
| Token lasts far longer than intended | expires was omitted, so the ten-year default applied |
| Worked interactively, fails from a script | The browser was sending a session cookie; the script needs its own token |