Security graph, risk, evidence and legal hold
One graph over every domain
Authpermit answers relationship questions over one logical graph: the trust graph (people, organizations, credentials, devices, canonical resources), your asset topology (what depends on, runs on, connects to what) and the AI operational graph (agents, models, tools, issues). A node is written type:id, e.g. asset:… or resource:…. Each question is one recursive database query, scoped to your organization in the query itself.
| Question | REST | MCP |
|---|---|---|
| What is this directly related to? | GET /api/v1/graph/neighbors?node= | authpermit_graph_neighbors |
| How are these two connected? | GET /api/v1/graph/path?from=&to= | authpermit_graph_path |
| What can this identity actually reach? | GET /api/v1/graph/reachable?node= | authpermit_graph_reachable |
| If this were compromised, what is exposed? | GET /api/v1/graph/blast-radius?node= | authpermit_graph_blast_radius |
| How could an attacker reach our crown jewels? | GET /api/v1/graph/attack-paths | authpermit_graph_attack_paths |
| What did the graph look like then? | GET /api/v1/graph/snapshot?at= | authpermit_graph_snapshot |
All need the graph:read scope and change nothing.
Provenance and time
Every edge says how Authpermit knows it: its source, its confidence (0–1), the table it came from and when it was last observed. Pass min_confidence to ignore guesses — an AI inference is never treated like an observed fact. Relationships are temporal: unlinking closes an edge instead of deleting it, so every query takes at to ask what held at a past moment.
Attack paths
An attack path starts at something internet-facing, passes through at least one node with an open high or critical finding, and ends at a crown jewel (critical, or holding sensitive data). Authpermit returns the shortest per entry and target, with an explanation and the evidence for each hop.
Risk signals and rollups
Risk scores are computed from signals: deduplicated, expiring facts about an entity (a compromised device, an open critical finding). A signal reported again refreshes rather than duplicates; one past its expiry stops counting and the entity is re-assessed. Your organization can publish its own scoring model (weights and level thresholds, versioned). GET /api/v1/risk/rollup (scope risk:read, MCP authpermit_risk_rollup) gives your posture by domain — identity, infrastructure, application, AI, third parties — and the riskiest entities; GET /api/v1/risk/signals lists the signals.
Evidence chain
Every command writes a hash-chained ledger entry that names the command and the event it emitted. GET /api/v1/evidence-links?command_id= (or event_id, decision_id, approval_id, resource_id; scope evidence:read, MCP authpermit_evidence_trace) returns the chain with its integrity.
Legal hold
A legal hold preserves data for a matter. While it is in force, the stored files, events and command records it covers are not purged, deleted or pruned, whatever their retention says — a deletion is refused and the refusal is recorded. A hold covers your whole organization or one target (a person, an asset, an owner of files, one file), optionally only some stores and only data created in a window.
- Place:
POST /api/v1/legal-holds/place(scopelegal_hold:manage, MCPauthpermit_legal_hold_place). Immediate. - Release:
POST /api/v1/legal-holds/{id}/releasewith a reason does not release anything: it opens an approval. People holdinglegal_hold:manage, at MFA, decide it — never the person who asked; two of them for a hold over the whole organization. Until it is approved the hold keeps holding; refused or expired, it stays in force. - Read:
GET /api/v1/legal-holds(scopelegal_hold:read).