Mojo UpDocs
Self-hosted AIOE

Tenancy and tokens

How AIOE keeps every organisation's data apart, and how people, workbenches and the platform prove who they are.

AIOE is built to serve more than one organisation from one deployment, even when you run it for yours alone. That shapes how it decides whose data a request may touch, and how every caller proves who it is.

Your organisation on every row

Everything AIOE stores, from enrolled devices to audit rows, is filed under an organisation (a tenant). Every read and write the API makes is limited to one organisation, and that organisation always comes from something AIOE verified:

CallerWhere the organisation comes from
A personThe issuer of their verified sign-in token.
A workbench or nodeThe token AIOE issued to it, which was bound to an organisation when a person approved it.
Anyone fetching the discovery documentThe host name the request arrived at, matched against your organisation's domains.

A request never chooses its organisation by naming one in its body.

People: the issuer selects the organisation

A person's access token comes from your identity provider. AIOE reads the token's issuer, finds the organisation configured with that issuer, and only then checks the token: its signature against the issuer's published keys, and its audience against your API registration. A token from any other issuer matches no organisation and is refused, so a token from one organisation's directory can never be read as another's.

From a verified token AIOE takes the person's ID (oid, or else sub), their roles (the roles claim) and, if present, their groups. It remembers roles and groups at each sign-in, because the tokens it issues to that person's workbench carry no claims of their own. A role or group change takes effect at the person's next sign-in.

Workbenches and nodes: tokens AIOE issues

A workbench never holds a person's sign-in. It enrols with the OAuth 2.0 device authorisation flow: it shows a code, a signed-in person approves it in the console, and AIOE issues the workbench its own tokens.

TokenLooks likeLivesNotes
Device codeaioe_dc_…10 minutes (24 hours for a node)Shown to the person as an eight-character code such as BCDF-2345.
Access tokenaioe_at_…1 hourOne token for ingest, catalogue, policy, fleet, relay and the overlay.
Refresh tokenaioe_rt_…30 daysReplaced on every use: a refresh issues a new pair and revokes the old refresh token.

Every token is random, carries a prefix that says what it is, and is stored only as its SHA-256 hash. The database never holds a usable token, so a copy of the database cannot be used to impersonate a workbench. Revoking a workbench in the console revokes all of its tokens at once.

Tokens bound to a key (DPoP)

A workbench can bind its tokens to a key pair it holds (DPoP, RFC 9449). It then sends each request with a fresh proof signed by that key, and AIOE refuses the token without one. A copied token is useless without the key, which never leaves the machine. AIOE accepts ES256 and EdDSA proofs, refuses a proof it has seen before (across every replica, through Redis), and refuses a bound token sent without a proof. The overlay agent signs its calls the same way, and the mesh relay checks those proofs too.

The platform's own signatures

When the platform sends remote control to a workbench over the overlay, it signs each request with its Ed25519 key, and publishes the public key at /.well-known/aioe-jwks.json, so the workbench can tell the platform from any other node on the network. The same key signs the short-lived peer tokens (ten minutes at most, used once) a person's workbench presents to a node. See Platform keys and rotation.

What a stored secret looks like

Values the platform holds for others (secrets for agents' tools, linked source-control accounts, workbench backups) are sealed with AES-256-GCM under AIOE_SECRETS_KEY and never shown again once stored. Credentials that stray into events, audit details or workbench backups are masked before they are stored: URL credentials, bearer and API tokens, JWTs, private keys, key=value secrets, command-line passwords, and fields named like credentials.

Authorisation per route

Every API route names who may call it: a workbench or node, a signed-in person, either, or an administrator. Within that, roles and project membership decide the rest: see People and roles.

On this page