Skip to content

Authentication

Axowl exposes several authentication mechanisms depending on the caller.

PrefixCallerAuth
/api/org/{slug}/*Dashboard (org member)Session token; org + membership resolved by TenantResolutionMiddleware.
/api/public/*SDK / end userApplication key and/or per-org RS256 JWT.
/api/m2m/tokenServer-to-serverExchanges an org API key (ah_live_…) for a short-lived token.
/scim/v2/{orgSlug}/*IdP provisioningSCIM bearer token.
/api/v1/admin/*Platform adminSession token.

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.

Sign in with an Axowl account (added 2026-09-26)

Section titled “Sign in with an Axowl account (added 2026-09-26)”

An app group can offer Continue with Axowl account as a sign-in method, next to passkey, email and social. People use the Axowl account they already have; the app still receives its own end-user token.

  • Turn it on in the dashboard: app group → Login methods → Sign in with Axowl account. It is always on while the app group is published on the marketplace. GET /api/public/apps/{applicationKey}/login-methods reports it as methods.axowlAccount.
  • The flow runs on the hosted portal (login.axowl.com/login/{applicationKey}/axowl), where the Axowl session cookie is readable. If the person is not signed in to Axowl, they go through the normal Axowl sign-in and come back.
  • The first time for an app group, the person sees what the app receives — name and email, nothing else — and must allow it. After that it is one click.
  • The end-user account is matched within the app’s organization by email, the same rule as social sign-in; a new one is created with provider Axowl. Only Axowl accounts with a verified email can use it.
  • The app gets the same token as any other method: sub is that organization’s end-user id. No Axowl account id, dashboard permission or other organization’s data is included.
Method · RoutePurpose
GET /api/v1/axowl-account/apps/{applicationKey}What would be shared, whether consent is needed, whether the method is on. Needs the Axowl session.
POST /api/v1/axowl-account/apps/{applicationKey}/connectBody { "consent": true } the first time. Returns the normal sign-in response (or the MFA step). 409 CONSENT_REQUIRED without consent the first time · 403 AXOWL_ACCOUNT_LOGIN_OFF when the method is off. Cookie-authenticated, so it needs X-CSRF-Token.

Apps installed by another organization (added 2026-09-27)

Section titled “Apps installed by another organization (added 2026-09-27)”

An organization can install a marketplace app for its people: Install for my organization on the marketplace, sealed by an Owner or Admin. It is the same switch as turning on a marketplace service — POST /api/org/{slug}/integrations/app:{groupKey}/enable — and it only works while the app group is published and is not the installer’s own app (404 APP_NOT_ON_MARKETPLACE, 400 OWN_APP).

When someone signs in to the app with their Axowl account, the token carries tenant_orgs: the organizations they are an active member of that installed this app group, as [{ "slug", "name" }]. Use it to open the right company workspace. It is computed only from a sign-in proven by the Axowl account (never from an email match), and it is recomputed on every token: a person who leaves the company, or an install that is removed, drops out on the next token. The OIDC /token response carries the same claim.

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.

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.

Terminal window
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.

  1. When issuing the key (POST /api/org/{slug}/settings/keys/api-keys, or Settings → Keys), set maxTokenLifetimeSeconds. 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 to api_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.
  2. When exchanging, pass lifetimeSeconds. The issued lifetime is min(lifetimeSeconds, key ceiling, 7 days), and the response’s expiresIn is the real value. Omitting lifetimeSeconds always yields the 5-minute default, even on a 7-day key — a longer token is something the device asks for explicitly.
Terminal window
curl -X POST https://testapi.axowl.com/api/m2m/token \
-H 'Content-Type: application/json' \
-d '{"orgSlug":"acme","apiKey":"ah_live_…","lifetimeSeconds":86400}'
RequestKey ceilingIssued
omittedany300
86400none (default key)300
864008640086400
6048008640086400
30any60 (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.