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.