Skip to content

Authentication

Spend has no passwords of its own. Each surface uses a different credential, and each is scoped to one tenant.

SurfaceCredentialWhere it comes from
REST API (/api/*)Authorization: Bearer <session token>Single sign-on, a passkey, or the sandbox’s POST /api/session
MCP server (/api/mcp)Authorization: Bearer <agent token>Administration › Connected agents, shown once
SCIM (/api/scim/v2)Authorization: Bearer <SCIM token>Administration › Sign-in and provisioning, shown once
Email intakex-spend-intake-secret headerINTAKE_EMAIL_SECRET on the server
Teams intakeTeams outgoing-webhook HMACTEAMS_INTAKE_SECRET_<TENANT>
E-invoice deliveryx-spend-einvoice-secret headerEINVOICE_INBOUND_SECRET_<TENANT>
Webhooks you receivex-spend-signature HMACThe subscription’s secret, shown once

A session token is 192 random bits, valid for 8 hours by default (SESSION_TTL_MINUTES) and revocable with POST /api/session/logout. The server stores only a SHA-256 hash of it, so a copy of the database holds no usable sessions.

  1. Send the browser to GET /api/auth/sso?tenant=<tenantId>&returnTo=/. The tenant’s configuration decides whether that is OpenID Connect or SAML.
  2. After the identity provider signs the person in, Spend redirects to /sso/complete#token=...&expiresInMinutes=...&returnTo=.... The token travels in the URL fragment, which never reaches server logs.

GET /api/auth/providers tells a client which tenants have single sign-on, whether the sandbox sign-in is on, and whether passkeys are.

POST /api/auth/passkey/options returns a WebAuthn challenge; POST /api/auth/passkey/verify with the device’s assertion returns a session like any other. Passkeys are bound to the host in PUBLIC_URL.

Every call runs as the person (or agent) the token belongs to. Role permissions are checked on each action, and segregation of duties is checked against the ledger history of the record, so the API can never do more than the same person could do in the web app.

For system-to-system reads, prefer webhooks or the event stream and the security feed, called with a session for a dedicated service account that holds only the audit or integration duty.