Authentication
Axowl exposes several authentication mechanisms depending on the caller.
Route taxonomy
Section titled “Route taxonomy”| Prefix | Caller | Auth |
|---|---|---|
/api/org/{slug}/* | Dashboard (org member) | Session token; org + membership resolved by TenantResolutionMiddleware. |
/api/public/* | SDK / end user | Application key and/or per-org RS256 JWT. |
/api/m2m/token | Server-to-server | Exchanges an org API key (ah_live_…) for a short-lived token. |
/scim/v2/{orgSlug}/* | IdP provisioning | SCIM bearer token. |
/api/v1/admin/* | Platform admin | Session token. |
End-user tokens (RS256)
Section titled “End-user tokens (RS256)”End-user JWTs are signed with the org’s RSA key and verified via the org’s published JWKS. Server-authoritative checks (Introspect, CheckPermission) read fresh permissions from the database (IdentityServiceImpl.cs:226), so revocations apply immediately.
Machine-to-machine
Section titled “Machine-to-machine”Use the API key directly. Org API keys are prefixed ah_live_ and presented as
Authorization: Bearer ah_live_… (IdentityServiceImpl.cs:124). They are SHA-256 hashed at rest,
scoped to a single organization, and can be rotated or revoked from Settings → Keys.
Token exchange (recommended for anything high-volume)
Section titled “Token exchange (recommended for anything high-volume)”POST /api/m2m/token trades the API key for a short-lived access token — 5 minutes by default.
Prefer it over sending the key on every call: the key is a long-lived secret, so each request that
carries it is another place it can leak (proxy logs, crash dumps, traces). The token expires on its
own and can be narrowed to fewer scopes than the key holds.
curl -X POST https://testapi.axowl.com/api/m2m/token \ -H 'Content-Type: application/json' \ -d '{"orgSlug":"acme","apiKey":"ah_live_…","scope":"org.member.read"}'{ "accessToken": "eyJhbGciOi…", "tokenType": "Bearer", "expiresIn": 300, "org": "acme" }Send it as Authorization: Bearer <accessToken> to /api/org/{slug}/*. The organization in the
token must match the {slug} in the route, and if the key is bound to a service account, that
account must still be active — both are re-checked on every request, so suspending the service
account takes effect immediately rather than when the token expires. Revoking the key also cuts
off tokens already issued from it, on the next request.
scope is optional and can only narrow what the key already has; it never widens it.
Longer-lived tokens for devices (added 2026-09-12)
Section titled “Longer-lived tokens for devices (added 2026-09-12)”Robots, gateways and other IoT devices lose connectivity and should not have to re-exchange every five minutes. The lifetime is a per-key ceiling, not an organization setting, so widening it for one device fleet changes nothing for your other keys.
- When issuing the key (
POST /api/org/{slug}/settings/keys/api-keys, or Settings → Keys), setmaxTokenLifetimeSeconds. Allowed values: 60 seconds to 7 days (604800). Anything above the default 300 requires the request to come from the organization owner and to carry the owner’s personal seal (assertionResponseJson, a passkey assertion bound toapi_key.long_lifetime). The dashboard collects the seal for you when you pick 1 hour, 24 hours or 7 days. Shorter-than-default ceilings need neither. A key’s ceiling cannot be changed afterwards — revoke and reissue. - When exchanging, pass
lifetimeSeconds. The issued lifetime ismin(lifetimeSeconds, key ceiling, 7 days), and the response’sexpiresInis the real value. OmittinglifetimeSecondsalways yields the 5-minute default, even on a 7-day key — a longer token is something the device asks for explicitly.
curl -X POST https://testapi.axowl.com/api/m2m/token \ -H 'Content-Type: application/json' \ -d '{"orgSlug":"acme","apiKey":"ah_live_…","lifetimeSeconds":86400}'| Request | Key ceiling | Issued |
|---|---|---|
| omitted | any | 300 |
86400 | none (default key) | 300 |
86400 | 86400 | 86400 |
604800 | 86400 | 86400 |
30 | any | 60 (floor) |
Revocation still wins: every /api/org/{slug}/* request checks the issuing key against a revocation
marker that is kept for the key’s full ceiling plus one hour, so a revoked 7-day key is refused on
the next call for the whole window. What the ceiling does widen is exposure — a leaked token is a
bearer credential for its entire lifetime until you revoke the key — which is why issuing one is an
owner-plus-seal action. Keep ceilings as short as the device’s offline pattern actually needs.