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 profile
  • write:profile — write your own profile
  • read:hcm / write:hcm — HCM read/write within your role's scope
  • admin:tenant — TENANT_ADMIN actions (rare; requires step-up at mint)
curl
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
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:

javascript
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:

  1. Your client calls the action endpoint. We refuse with 401 STEP_UP_REQUIRED + a purpose field.
  2. Client POSTs /api/auth/step-up/challenge-options with the purpose.
  3. User completes the ceremony (WebAuthn or TOTP). We mint an HMAC-signed step-up token.
  4. 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.