Authentication
The platform issues four kinds of credentials. Pick the one that matches your caller.
Session cookie (NextAuth)
Set when a human signs in at /auth/login. Carries the NextAuth JWT in authjs.session-token. Used by the dashboard and by any API the user calls from the browser.
Sign-in flow is rate-limited (10 attempts / 5 min / IP for TOTP, 5 / 5 min / IP for recovery codes) and enforces MFA + network policy + step-up where configured.
Personal Access Token (PAT)
For YOU acting as YOU via the API. Mint at /account/security → Personal access tokens. Format pat_…; bcrypt- hashed at rest, shown ONCE at creation.
Scopes (multi-select at mint time):
read:profile— read your own profilewrite:profile— write your own profileread:hcm/write:hcm— HCM read/write within your role's scopeadmin:tenant— TENANT_ADMIN actions (rare; requires step-up at mint)
curl https://app.axissynapse.com/api/me/profile \
-H "Authorization: Bearer $AXISSYNAPSE_PAT"SCIM 2.0 bearer token
For your IdP's SCIM connector (Okta, Entra, JumpCloud). Mint at /settings → Identity & SSO → SCIM 2.0 provisioning tokens. Format scim_…; the raw value is shown ONCE.
Send as Authorization: Bearer scim_… with Accept: application/scim+json. Scoped to the tenant that minted the token.
curl https://app.axissynapse.com/api/scim/v2/Users \
-H "Authorization: Bearer $SCIM_TOKEN" \
-H "Accept: application/scim+json"Webhook signing secret
Per-subscription HMAC-SHA256 key. NOT a credential you send — it's how AxisSynapse signs the events we deliver to you. Mint at /settings → Webhooks → Add webhook. Format whsec_…; shown ONCE.
On each delivery we send two headers your receiver MUST verify:
X-AxisSynapse-Signature: v1=<hex>X-AxisSynapse-Timestamp: <unix-seconds>
Verification recipe:
import { createHmac, timingSafeEqual } from "node:crypto";
function verify(rawBody, sigHeader, tsHeader, secret) {
const tolerance = 300; // 5-minute replay window
const ts = Number(tsHeader);
if (!Number.isFinite(ts)) return false;
if (Math.abs(Date.now() / 1000 - ts) > tolerance) return false;
const expected = "v1=" + createHmac("sha256", secret)
.update(`${ts}.${rawBody}`).digest("hex");
const a = Buffer.from(sigHeader);
const b = Buffer.from(expected);
return a.length === b.length && timingSafeEqual(a, b);
}A live verifier (paste payload + signature + secret → green/red) is at /developers/webhook-verifier.
Step-up authentication tokens
High-impact actions (payroll transmit, equity cosign, erasure finalize, etc.) require a fresh second-pass proof. The flow is:
- Your client calls the action endpoint. We refuse with
401 STEP_UP_REQUIRED+ apurposefield. - Client POSTs
/api/auth/step-up/challenge-optionswith the purpose. - User completes the ceremony (WebAuthn or TOTP). We mint an HMAC-signed step-up token.
- Client retries the original action with
X-StepUp-Token: <token>.
Tokens are single-use, IP-bound, 60s default TTL. The closed set of purposes is in the API reference.