Authentication

People: signed-in sessions

People sign in with a magic link or email and password. The session lives in a cookie and is refreshed on each request.

  • Two-factor authentication. Anyone can enrol an authenticator app. Organization admins can require two-factor for every member; a session without it is then refused by the portals and the APIs.
  • Session controls. Members can sign out of every other device. Admins can sign a member out and set how long an idle session lasts for their organization.
  • Cross-site protection. Requests that change data and are authenticated by the cookie must come from an allowed origin. See the GraphQL CSRF rule.

Programs: API keys

| | | |---|---| | Header | X-API-Key: <key> (the MCP server also accepts Authorization: Bearer <key>) | | Storage | Only a SHA-256 hash is stored. The plaintext is shown once, at creation. | | Expiry | Optional. Expired, revoked and unknown keys are rejected identically. | | Revocation | Immediate — keys are checked on every request, never cached. | | Where | The API keys page of the carrier portal (Exports). |

Scopes

A key can only do what its scopes allow. A key with no scopes can do nothing.

| Scope | Grants | |---|---| | mcp | The read-only MCP server | | graphql | The GraphQL API. Granted only to keys created by After Action staff accounts. | | carrier_read | The carrier partner readiness feed | | kpi_ingest | Submitting KPI values | | field_intakes:read | Reading field intake records |

Client portal accounts cannot create API keys today. Contact us if you need programmatic access.

Roles

Every request carries a role that decides what it can see and do.

| Role | Access | |---|---| | owner, admin, ops | After Action staff: engagements, exercises, reports and deliverables for the clients they serve | | client | Your own organization's exercises, readiness, gaps, reports and deliverables | | carrier | Readiness posture of the policyholders that have partnered with the carrier |

Data isolation

Every table enforces row-level security in the database, so a session can only read rows its organization is entitled to, even if application code made a mistake. Server-side code that needs elevated access never runs in the browser.