Skip to content

Authentication

Consystence accepts three credentials, and the one a client sends depends on who or what is calling:

  • People in a browser or the CLI sign in with their organisation account (Microsoft Entra External ID, at id.consystence.com) and send the resulting Bearer token.
  • Scripts, integrations and CI jobs send a tenant API key in the X-Api-Key header.
  • People at a site server can sign in with their email and a site PIN, which works without a connection to the cloud.

This page describes each credential, how the server tells them apart, what each one proves, and the account flows that belong to the identity provider rather than to Consystence.

The server chooses how to validate a request from the credential it carries:

flowchart TD
    R[Incoming request] --> Q{X-Api-Key header?}
    Q -- yes --> AK[Tenant API key]
    Q -- no --> B{Authorization: Bearer?}
    B -- "no" --> NR[401]
    B -- "yes" --> ISS{"Issuer consystence-local?"}
    ISS -- "yes (site server)" --> L[Site-PIN token]
    ISS -- no --> E[Organisation sign-in token]
Request carriesValidated asNotes
X-Api-Key onlyTenant API key
Authorization: Bearer … onlyOrganisation sign-in token or site-PIN tokenChosen by the token’s issuer: site-PIN tokens are issued as consystence-local
Both X-Api-Key and AuthorizationTenant API keyThe API key is used and the request is not rejected (HTTP clients commonly set both)
Neither—401

The issuer only selects the validator. That validator then checks the token’s signature, issuer, audience and lifetime in full, so a token that names an issuer it was not signed by is rejected. Site-PIN tokens are accepted by site servers only; the hosted service rejects them.

A SignalR WebSocket handshake cannot carry an Authorization header, so on /hubs paths the server also reads the Bearer token from the ?access_token= query string and applies the same issuer-based choice. This is how a site-PIN token reaches the live console on a site server. A query-string token on any other path is ignored.

For organisation membership, the stable identity of a person is their Entra object id (oid) — the tenant-immutable object id that resolves one person to one identity at the account and at every cell. Email is a verified attribute and an invitation channel, never the membership key. A @gmail.com account can hold different roles in two different organisations simultaneously, keyed on the same oid.

Roles are not asserted by the identity provider. An Entra token carries the oid but no Consystence role; when the server authenticates a request, it resolves the tenant from the request subdomain and the person’s role in that tenant from their membership. See Roles & Permissions for the role model (owner / admin / member).

What each credential establishes:

Organisation sign-inAPI keySite PIN
Who is callingThe person, by their oidThe key itself (its keyId); an operator key also names the person it acts forThe site user
TenantResolved from the oid and the request subdomainThe tenant the key was created inNone in the token; a site server serves its own enrolled tenant
RoleThe person’s membership role, resolved by the serverA read-only key’s member or admin role; an operator key carries no tenant role, only its site and personNo organisation role; the token carries the user’s site role

The credential for browsers and interactive users. Identity is provided by Entra External ID (CIAM) — the id.consystence.com identity provider. The browser obtains a token through an OpenID Connect authorization-code flow with PKCE, which the server drives against the provider’s published discovery document:

  • GET /auth/login — builds the authorize URL (resolved from the provider’s /.well-known/openid-configuration) and redirects the browser to the IdP.
  • GET /auth/callback — validates state, exchanges the code (with the PKCE verifier) for tokens, and establishes a server-side session.
  • POST /auth/token — returns the access token for the SignalR connection (POST so it never lands in logs or history).
  • POST /auth/logout — clears the session.

The CLI obtains the same organisation sign-in token through its own PKCE flow with a localhost loopback redirect — see the CLI client.

Tokens are validated against the configured authority with clock skew tightened to one minute. Entra External ID may issue either the v2.0 issuer or the legacy v1.0 issuer depending on endpoint and token type, so both forms are accepted on issuer validation. Each cell validates organisation sign-in tokens directly — token validation is local to the server handling the request and does not call back to the account control plane on the request path.

Programmatic and partner integrations authenticate with a tenant API key sent in the X-Api-Key header. Keys are:

  • Prefixed csk_ — a high-entropy random value generated by a CSPRNG (the exact length and encoding are an implementation detail).
  • Stored hashed, never in plaintext. Only the hash and a short display prefix (csk_ + the first 4 characters) are persisted.
  • Tenant-scoped — a key belongs to the tenant it was created in and cannot act outside it.
  • Read-only unless created as an operator key. A read-only key reads tenant and site data; it never writes, commands, acknowledges or administers anything, whatever its role. Its role is member or admin, never owner and never above its creator’s, and decides only which reads the key may make. An operator key is the one class with write authority. An organisation owner or admin, signed in with their organisation account, creates it for one site and one named person. It lives at most 30 days and is never renewed. It is valid only while that site accepts Consystence commands (a native site) and that person may still command, and it holds an operator’s authority on that site, never an administrator’s: it can issue commands and acknowledge alarms there. An API key cannot create or revoke keys.

An unknown, revoked or expired key is refused with a uniform 401.

Tenant keys are managed under /api/admin/api-keys by an organisation owner or admin (see Roles & Permissions). On a site server, a site user whose site role is Owner or Admin can also manage keys and creates member keys only; a Site admin lists and revokes keys but does not create them. The request and response shapes are on Tenant API keys.

MethodPathBehaviour
POST/api/admin/api-keysCreate a key: read-only by default, or an operator key bound to one site and one person. Plaintext is returned exactly once in the 201 body — capture it then; no later call re-emits it.
GET/api/admin/api-keysList keys for the caller’s tenant — prefix and metadata only, never plaintext or hash.
DELETE/api/admin/api-keys/{keyId}Revoke a key. Cross-tenant or unknown ids both return a uniform 404.

Keys carry a required expiry: expiresAt must be supplied when creating a key — there is no server-side default (the web form and the CLI propose 90 days for a read-only key and 7 days for an operator key). A read-only key’s expiry must lie between one hour and two years from now; an operator key lives 1 to 30 days and is replaced by issuing a new key. Anything outside the window is rejected with a 400. For a read-only key, a reminder is emailed to the key’s creator 24 to 30 days before it expires. The tenant is always derived from the authenticated caller, never from the request body — a caller cannot widen scope by editing the payload.

Industrial sites — mining and CHPP plants — must keep operating when the upstream link is down. Site-PIN sign-in exists for exactly this: a site-resident, offline-capable sign-in that does not depend on reaching Entra.

A site user signs in with email plus a numeric site PIN (POST /auth/site/login). The PIN is stored hashed, and repeated failures lock the account. On success the server issues a short-lived (one-hour) access JWT signed by a local key, with issuer consystence-local and audience consystence-api, validated against the server’s local JWKS endpoint — plus a seven-day rotating refresh token. The consystence-local issuer is how the server recognises a site-PIN token (see Which credential to send).

The scheme carries its own token lifecycle:

  • POST /auth/site/refresh — exchanges the refresh token for a new access + refresh pair; the old refresh token is revoked on rotation. Presenting a refresh token that was already rotated is treated as theft and ends all of that user’s site sessions. A refresh token from a session that was signed out, or ended by an administrator, is simply refused.
  • POST /auth/site/logout — ends the session of the presented refresh token.
  • POST /auth/site/verify-email / POST /auth/site/verify-otp — first-login email verification: a six-digit OTP is emailed to the address and, once confirmed, marks the site user’s email verified.
  • POST /auth/site/create-pin — sets or changes the caller’s PIN (minimum six digits; requires an authenticated session, organisation sign-in or site PIN; a site-PIN session also gives its current PIN).
  • POST /auth/site/forgot-pin / POST /auth/site/reset-pin — resets a forgotten PIN with an emailed code; the reset ends every session of that user.
  • GET /auth/site/me — returns the current user as asserted by the token.

Sign-in, refresh and sign-out need no cloud connection. Email verification and the forgot-PIN reset send their code through the site server’s email service, where one is configured.

A site-PIN token carries the user’s site role and no organisation claims (no oid, org_slug or org_role; see Roles & Permissions), and the hosted cloud service does not accept it.

Site users exist on site servers only, and are administered on the site server itself under /api/site/users. A site user whose site role is Owner, Admin or Site admin manages them, fully offline; so does an organisation owner or admin signed in with their organisation account. A Site admin gives no role above its own (see Site roles on a site server).

MethodPathBehaviour
GET/api/site/usersList site users with role, verification, lock, and enabled status.
POST/api/site/users/provisionPre-authorise a user before they arrive on-site: email + display name + site role, optionally with a temporary PIN (minimum six digits). A user provisioned with a PIN can sign in immediately — including during a cloud outage.
PUT/api/site/users/{userId}/roleUpdate the user’s site role.
POST/api/site/users/{userId}/unlockClear a PIN lockout (resets failed attempts).
POST/api/site/users/{userId}/one-time-pinIssue a one-time PIN, shown once, for a user who has forgotten theirs. It replaces the user’s PIN at once, ends their sessions, and works once, at a sign-in that sets a new PIN.
DELETE/api/site/users/{userId}Disable the user (soft delete — revokes site access).

The organisation account belongs to Entra External ID. Sign-up, passwords, second factors, credential recovery and the token lifecycle of that account are the identity provider’s job, and Consystence never sees or stores the account’s password. Consystence consumes the provider’s OIDC discovery document; it does not serve one of its own.

Platform administration is a Consystence operations capability, used for support, diagnostics and onboarding. It is not an organisation role and not the licensing authority (see Licensing and Platform administrators).

Authentication establishes who; the caller’s role decides what. Organisation administration — members, sites, credentials and configuration — needs an owner or admin membership role, and tenant reads need any membership role. The role is the caller’s role in the organisation the request is for, resolved by the server, never read from the token. An API key is further limited by its class: a read-only key only reads, and an operator key acts only on its one site. On a site server, a person signed in by site PIN acts on their site role. The full role model lives in Roles & Permissions.