NHI Management API

Manage Non-Human Identities (NHIs) as first-class entities with dedicated lifecycles, ownership, authorization modes, and governance. NHIs include service accounts, AI agents, CI/CD pipelines, IoT devices, and any automated system that requires authorization.

Base Path

/api/v1/tenant/nhis

All endpoints require X-Tenant-ID and Authorization: Bearer headers.

Key Concepts

Tiering (0-3)

Tier 0: critical infrastructure. Tier 3: dev/test. Tier determines JIT TTL, rotation overlap, and escalation paths.

State Machine (13 states)

provisioned → active → pending_attestation → expired/revoked → archived → purged. Guards enforce Tier-based transitions.

Authorization Modes

standalone, impersonate_live, impersonate_snapshot, autonomous, dynamic_jit, offline_capability

Self-Repair

SCIM departure events trigger automatic ownership reassignment via priority chains. Security incidents revoke immediately.

Registry CRUD

Create, list, get, and update Non-Human Identities.

POST/api/v1/tenant/nhis

Register a new NHI with initial ownership. technicalOwner is required.

Request BodyJSON
{
  "name": "payment-processor-prod",
  "displayName": "Payment Processor (Production)",
  "actorType": "service_account",
  "actorSubtype": "microservice",
  "environment": "production",
  "tier": 1,
  "dataClassification": "confidential",
  "authorizationMode": "standalone",
  "expiresAt": "2027-07-01T00:00:00Z",
  "tags": { "team": "payments", "cost_centre": "CC-4200" },
  "businessContext": { "department": "Finance", "criticality": "high" },
  "owners": {
    "technicalOwner": {
      "assigneeId": "jane.smith",
      "assigneeEmail": "jane.smith@nhs.net",
      "orgId": "org-platform-eng"
    },
    "businessOwner": {
      "assigneeId": "mark.director",
      "assigneeEmail": "mark.director@nhs.net",
      "orgId": "org-finance"
    },
    "deputies": [
      {
        "assigneeId": "bob.senior",
        "assigneeEmail": "bob.senior@nhs.net",
        "orgId": "org-platform-eng"
      },
      {
        "assigneeId": "alice.backup",
        "assigneeEmail": "alice.backup@nhs.net",
        "orgId": "org-platform-eng"
      }
    ],
    "escalationContacts": [
      {
        "assigneeType": "group",
        "assigneeId": "grp-platform-oncall",
        "orgId": "org-platform-eng"
      },
      {
        "assigneeType": "user",
        "assigneeId": "vp-engineering",
        "assigneeEmail": "vp.eng@nhs.net",
        "orgId": "org-engineering"
      }
    ]
  }
}
Response (201)JSON
{
  "nhi": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "tenantId": "your-tenant-id",
    "name": "payment-processor-prod",
    "displayName": "Payment Processor (Production)",
    "actorType": "service_account",
    "environment": "production",
    "tier": 1,
    "dataClassification": "confidential",
    "authorizationMode": "standalone",
    "currentState": "provisioned",
    "managementStatus": "pending_acceptance",
    "validFrom": "2026-07-28T10:00:00Z",
    "expiresAt": "2027-07-01T00:00:00Z",
    "attestationWindowDays": 30,
    "createdAt": "2026-07-28T10:00:00Z",
    "updatedAt": "2026-07-28T10:00:00Z"
  },
  "owners": [
    { "id": "...", "role": "technical_owner", "assigneeId": "jane.smith", "acceptanceStatus": "pending", "priority": 1 },
    { "id": "...", "role": "business_owner", "assigneeId": "mark.director", "acceptanceStatus": "pending", "priority": 1 },
    { "id": "...", "role": "deputy", "assigneeId": "bob.senior", "acceptanceStatus": "pending", "priority": 1 },
    { "id": "...", "role": "deputy", "assigneeId": "alice.backup", "acceptanceStatus": "pending", "priority": 2 },
    { "id": "...", "role": "escalation_contact", "assigneeId": "grp-platform-oncall", "acceptanceStatus": "pending", "priority": 1 },
    { "id": "...", "role": "escalation_contact", "assigneeId": "vp-engineering", "acceptanceStatus": "pending", "priority": 2 }
  ]
}

Ownership structure:

  • technicalOwner — required, single object. The engineer responsible for the NHI.
  • businessOwner — optional (recommended Tier 0-1), single object. The business stakeholder.
  • deputies[] — optional, ordered array. Backup owners promoted during self-repair. Priority = array index.
  • escalationContacts[] — optional, ordered array. Notified when deputies are exhausted. Can be groups.
GET/api/v1/tenant/nhis

List NHIs with optional filters. Cursor-based pagination.

Query Parameterstext
?state=active            Filter by state
?environment=production  Filter by environment
?tier=0                  Filter by tier (0-3)
?limit=50               Page size (max 100)
?cursor=base64...        Pagination cursor
Response (200)JSON
{
  "data": [
    { "id": "...", "name": "payment-processor-prod", "currentState": "active", "tier": 1, ... }
  ],
  "nextCursor": "eyJjcmVhdGVkX2F0IjoiMjAyNi0wNy0yOFQxMDowMDowMFoifQ=="
}
GET/api/v1/tenant/nhis/:id

Get a single NHI by ID.

PATCH/api/v1/tenant/nhis/:id

Update mutable fields (display_name, tags, business_context, dr_config).

Lifecycle Management

Transition NHIs through their state machine. Guards enforce Tier-based rules.

State Machine

provisioned → pending_activation → active → pending_attestation → expired/revoked → archiving → archived → purge_pending → purged. Tier 0-1 NHIs that miss attestation go to suspended_requiring_ciso_approval instead of auto-expiring.

POST/api/v1/tenant/nhis/:id/activate

Transition from pending_activation → active.

Response (200)JSON
{ "message": "NHI activated" }
POST/api/v1/tenant/nhis/:id/revoke

Immediately revoke an NHI. Triggers credential revocation cascade.

Request BodyJSON
{ "reason": "security_incident_2026_07" }
POST/api/v1/tenant/nhis/:id/renew

Renew/attest an NHI. Extends expiry and returns to active state.

Request BodyJSON
{
  "newExpiresAt": "2027-12-31T23:59:59Z"
}

Authorization Modes

Configure how an NHI obtains permissions. Each mode maps to a different SpiceDB tuple pattern.

ModeDescriptionSpiceDB Pattern
standaloneDirect permission assignmentnhi:X#permission@resource:Y
impersonate_liveLive delegation from a user (consent required)nhi:X#impersonates@user:Y [caveated]
impersonate_snapshotSnapshot of user permissions at bind timeCached permission set
autonomousBounded scope + Beyond Zero oversightnhi:X#autonomous_scope@scope:Y
dynamic_jitEphemeral per-task tokens (5-60min TTL)Caveated tuple per token
offline_capabilityPre-signed for disconnected PDPCapability token
POST/api/v1/tenant/nhis/:id/mode

Set the authorization mode. Some modes require additional config.

Request Body (standalone)JSON
{ "mode": "standalone" }
Request Body (impersonate_live)JSON
{
  "mode": "impersonate_live",
  "bindingConfig": {
    "userId": "dr-smith",
    "userEmail": "dr.smith@nhs.net",
    "bindingType": "live",
    "bindingExpiresAt": "2027-01-01T00:00:00Z",
    "permissionConstraints": ["view_record", "edit_record"],
    "resourceScope": { "ward": "cardiology-a3" }
  }
}

Dynamic JIT Tokens

Issue ephemeral, task-scoped tokens for AI agents and automation. Each token creates a caveated SpiceDB tuple that auto-expires. Max 50 active tokens per NHI.

TTL by tier: Tier 0: 5min | Tier 1: 10min | Tier 2: 30min | Tier 3: 60min

POST/api/v1/tenant/nhis/:id/jit

Issue a JIT token for a specific task. NHI must be in dynamic_jit mode and active state.

Request BodyJSON
{
  "resourceId": "patient-record-1234",
  "operation": "summarize",
  "justification": "Clinical summary for ward round",
  "missionId": "mission-abc-123"
}
Response (201)JSON
{
  "token": {
    "token": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
    "expiresAt": "2026-07-28T10:10:00Z",
    "scope": ["summarize"],
    "nhiId": "550e8400-e29b-41d4-a716-446655440000"
  }
}
DELETE/api/v1/tenant/nhis/jit/:tokenId

Revoke a JIT token before natural expiry.

Response (200)JSON
{ "revoked": true }

Impersonation Bindings

Manage consent-gated impersonation bindings between NHIs and users. Users must explicitly grant consent before an NHI can act on their behalf.

GET/api/v1/tenant/nhis/:id/bindings

List active bindings for the current user.

POST/api/v1/tenant/nhis/:id/bindings/consent

Grant consent to a pending binding.

Request BodyJSON
{ "bindingId": "binding-uuid-here" }
DELETE/api/v1/tenant/nhis/:id/bindings/:bindingId

Revoke consent — immediately deactivates binding and removes SpiceDB tuple.

Credential Lifecycle

Issue, rotate, and revoke credentials. Rotation enforces tier-based overlap windows to prevent downtime during rolling deployments.

Rotation overlap: Tier 0-1: 5 minutes | Tier 2-3: 24 hours. Both old and new credentials remain valid during the overlap window.

GET/api/v1/tenant/nhis/:id/credentials

List all credentials for an NHI (active, rotated, revoked).

POST/api/v1/tenant/nhis/:id/credentials

Issue a new credential.

Request BodyJSON
{
  "credentialType": "api_key",
  "secretProvider": "authhub_hsm",
  "expiresAt": "2027-01-01T00:00:00Z"
}
Response (201)JSON
{
  "credential": {
    "id": "cred-uuid",
    "nhiId": "nhi-uuid",
    "credentialType": "api_key",
    "credentialRef": "ref-uuid",
    "status": "active",
    "issuedAt": "2026-07-28T10:00:00Z",
    "expiresAt": "2027-01-01T00:00:00Z",
    "rotationCount": 0,
    "secretProvider": "authhub_hsm"
  }
}
POST/api/v1/tenant/nhis/:id/credentials/:credId/rotate

Rotate a credential. Issues new + keeps old alive during overlap.

DELETE/api/v1/tenant/nhis/:id/credentials/:credId

Revoke immediately (< 60s propagation). Publishes revocation event.

Request BodyJSON
{ "reason": "compromised_key" }

Credential Types

TypeUse Case
api_keyStandard API key (HSM-backed)
oauth_clientOAuth 2.0 client credentials
mtls_certMutual TLS certificate
wifWorkload Identity Federation (RFC 8693)
spiffeSPIFFE SVID (service mesh)
offline_capabilityPre-signed capability for disconnected PDP

Dependency Graph

Map relationships between NHIs and external systems. Supports impact analysis before revocations.

GET/api/v1/tenant/nhis/:id/dependencies

List all dependencies (upstream and downstream).

POST/api/v1/tenant/nhis/:id/dependencies

Add a dependency relationship.

Request Body (external service)JSON
{
  "targetType": "external_service",
  "targetExternalRef": "stripe-api",
  "targetDisplayName": "Stripe Payment API",
  "direction": "upstream",
  "dependencyType": "hard",
  "discoveryMethod": "manual"
}
Request Body (NHI-to-NHI dependency)JSON
{
  "targetType": "nhi",
  "targetNhiId": "550e8400-e29b-41d4-a716-446655440000",
  "targetDisplayName": "Auth Token Service",
  "direction": "upstream",
  "dependencyType": "hard",
  "discoveryMethod": "automated"
}
DELETE/api/v1/tenant/nhis/:id/dependencies/:depId

Remove a dependency.

GET/api/v1/tenant/nhis/:id/impact

Impact analysis: what breaks if this NHI is revoked?

Response (200)JSON
{
  "analysis": {
    "nhiId": "nhi-uuid",
    "directDependents": [
      { "sourceNhiId": "other-nhi", "targetType": "nhi", "dependencyType": "hard", "direction": "upstream" }
    ],
    "transitiveDependents": [],
    "hardDependencyCount": 1,
    "riskLevel": "medium"
  }
}

Certification Campaigns

Run periodic attestation campaigns. NHIs in scope must be certified (renewed) or revoked before the deadline. Unattested NHIs auto-expire when the campaign closes.

GET/api/v1/tenant/nhis/campaigns

List all campaigns for the tenant.

POST/api/v1/tenant/nhis/campaigns

Create a new certification campaign.

Request BodyJSON
{
  "name": "Q3 2026 Production NHI Review",
  "scopeFilter": {
    "environment": "production",
    "tier": 1
  },
  "deadline": "2026-09-30T23:59:59Z",
  "completionThreshold": 95.0
}
Response (201)JSON
{
  "campaign": {
    "id": "campaign-uuid",
    "name": "Q3 2026 Production NHI Review",
    "status": "active",
    "totalInScope": 42,
    "certified": 0,
    "revoked": 0,
    "deadline": "2026-09-30T23:59:59Z"
  }
}
GET/api/v1/tenant/nhis/campaigns/:id

Get campaign progress.

Response (200)JSON
{
  "progress": {
    "campaignId": "campaign-uuid",
    "total": 42,
    "certified": 35,
    "revoked": 3,
    "pending": 4,
    "percentComplete": 90.5,
    "onTrack": true
  }
}
POST/api/v1/tenant/nhis/campaigns/:id/certify

Certify (attest) an NHI within a campaign.

Request BodyJSON
{
  "nhiId": "nhi-uuid",
  "newExpiresAt": "2027-03-31T23:59:59Z"
}
POST/api/v1/tenant/nhis/campaigns/:id/revoke

Revoke an NHI within a campaign (decided not to renew).

Request BodyJSON
{
  "nhiId": "nhi-uuid",
  "reason": "Service deprecated — migrated to new platform"
}
DELETE/api/v1/tenant/nhis/campaigns/:id

Cancel an active campaign (admin action).

Ownership Management

Dual governance: every NHI requires both a technical_owner and a business_owner. Deputies and escalation contacts provide fallback chains for self-repair.

GET/api/v1/tenant/nhis/:id/owners

List all owners for an NHI, ordered by role and priority.

POST/api/v1/tenant/nhis/:id/owners

Assign a new owner. Acceptance is required (status starts as pending).

Request BodyJSON
{
  "role": "technical_owner",
  "assigneeType": "user",
  "assigneeId": "jane.smith",
  "assigneeEmail": "jane.smith@nhs.net",
  "orgId": "org-engineering",
  "priority": 1
}
Response (201)JSON
{
  "owner": {
    "id": "owner-uuid",
    "nhi_id": "nhi-uuid",
    "role": "technical_owner",
    "assignee_id": "jane.smith",
    "acceptance_status": "pending",
    "assigned_by": "current-user",
    "assignment_type": "manual"
  }
}

Ownership Rules

  • One accepted technical_owner per NHI (unique constraint)
  • One accepted business_owner per NHI (unique constraint)
  • Multiple deputies allowed (distinguished by priority)
  • Unaccepted assignments escalate after 72 hours
  • Self-repair auto-promotes senior deputies on owner departure

JML Lifecycle

NHIs follow a Joiner/Mover/Leaver lifecycle analogous to human identities, but triggered by API calls and automated governance rather than HR processes.

Joiner (Provisioning)

An NHI is created via POST /nhis with at minimum a technicalOwner. The NHI entersprovisioned state, and ownership assignments start as pending until accepted.

EventState TransitionTrigger
Registered→ provisionedPOST /nhis
Credentials bound→ pending_activationPOST /nhis/:id/credentials
Activated→ activePOST /nhis/:id/activate (or valid_from reached)

Mover (In-life Changes)

Active NHIs undergo mutations without leaving the active state family. These are audited as mover events.

EventEndpoint
Credential rotationPOST /nhis/:id/credentials/rotate
Permission changePATCH /nhis/:id (authorizationMode, tier)
Ownership transferPOST /nhis/:id/owners + accept/decline
Mode changePOST /nhis/:id/mode
Renewal / attestationPOST /nhis/:id/renew

Leaver (Decommissioning)

NHIs exit through revocation, expiry, or explicit decommission. Credential revocation cascades immediately; archival and purge follow retention policies.

EventState TransitionTrigger
Revoked→ revokedPOST /nhis/:id/revoke or security incident
Expired→ expiredAttestation deadline missed (Tier 2-3)
Decommissioned→ archivingDELETE /nhis/:id
Archived→ archivedRetention archival job
Purged→ purgedRetention purge job (GDPR-compliant)

Tier 0-1 Exception

Critical NHIs (Tier 0-1) never auto-expire. Instead, missed attestation deadlines transition to suspended_requiring_ciso_approval. Only a CISO-role user can resume or force-revoke.

SCIM & Human Owner Dependency

NHI ownership is anchored to real humans synced via SCIM. When an owner departs the organisation, the self-repair engine detects the event and cascades through the priority chain to maintain continuous governance.

How It Works

  1. 1IdP pushes SCIM active: false or a custom departure extension to AuthHub
  2. 2Self-repair engine queries all NHIs where the departed user is an accepted owner
  3. 3Senior deputy is promoted to technical_owner (priority-ordered)
  4. 4If no deputy exists or all decline within 72h, escalation contacts are notified
  5. 5If unresolved, NHI transitions to degraded → eventually unmanaged

Departure Types

AuthHub supports a SCIM custom extension that classifies departure events. If not provided, the system falls back to treating active: false as a permanent termination with a 72-hour grace period.

Departure TypeSelf-Repair ActionTimeline
permanent_terminationPromote deputy immediatelyInstant
security_incidentRevoke all NHI bindings + promote deputyInstant (no grace period)
temporary_leave_shortAssign interim owner, revert on return72h before promoting
temporary_leave_longPromote deputy (may revert on return)Immediate
role_changeOwnership transfer to successor if hinted72h grace
team_disbandedBulk repair triggered, escalation contacts notifiedImmediate

Why Deputies Matter

An NHI created without deputies or escalation contacts has no self-repair path. If the sole technical owner departs, the NHI immediately enters unmanaged state and will be flagged for CISO review (Tier 0-1) or eventually auto-revoked (Tier 2-3, after max unmanaged duration).

Minimum Ownership Requirements

FieldRequired?Recommendation
technicalOwnerRequiredAlways
businessOwnerOptionalStrongly recommended for Tier 0-1
deputies[]OptionalAt least 1 for production NHIs (enables self-repair)
escalationContacts[]OptionalRequired by policy for Tier 0 (org-level groups preferred)

SCIM Extension Schema

IdPs that support custom schemas can push rich departure context via this extension. If unavailable, AuthHub infers departure type from the standard active: false signal.

Extension URItext
urn:ietf:params:scim:schemas:extension:authhub:nhi:2.0:User
Extension AttributesJSON
{
  "departureType": "permanent_termination | security_incident | temporary_leave_short | ...",
  "effectiveDate": "2026-09-01T00:00:00Z",
  "expectedReturnDate": "2026-12-01T00:00:00Z",
  "securityIncident": false,
  "successorUserId": "bob.senior",
  "handoverCompleted": true
}

SLOs

MetricTarget
SCIM event to repair initiated< 5 minutes (P95)
Security incident to NHI revocation< 60 seconds
NHIs without owner (steady state)< 1%
Unaccepted assignment escalation72 hours

Anomaly Detection

Real-time behavioural anomaly detection for NHI access patterns. Critical anomalies auto-degrade the NHI state; warnings are logged for review.

GET/api/v1/tenant/nhis/:id/anomalies

Get recent anomaly events for an NHI.

Response (200)JSON
{
  "anomalies": [
    {
      "id": "event-uuid",
      "nhiId": "nhi-uuid",
      "anomalyType": "rate_spike",
      "severity": "warning",
      "details": { "requestsPerMinute": 750 },
      "detectedAt": "2026-07-28T09:45:00Z",
      "resolved": false
    },
    {
      "id": "event-uuid-2",
      "nhiId": "nhi-uuid",
      "anomalyType": "dormancy_violation",
      "severity": "warning",
      "details": { "daysSinceLastAuth": 95 },
      "detectedAt": "2026-07-27T14:00:00Z",
      "resolved": false
    }
  ]
}

Anomaly Types

TypeTriggerAuto-Response
dormancy_violationNHI inactive >90 days suddenly activeWarning logged
rate_spike>500 req/min (warning) or >1000 (critical)Critical: auto-degrade
credential_sharingSame credential used from multiple IPsWarning logged
permission_escalationSudden increase in permission requestsWarning logged
cross_tenant_probeNHI attempts to access other tenantsCritical: auto-degrade

Governance and Reporting

Ownership acceptance, decommissioning, dormancy reporting, estate health, and self-repair visibility.

Ownership Acceptance

POST/api/v1/tenant/nhis/:id/owners/:ownerId/accept

Accept an ownership assignment. Transitions NHI to healthy when all primary owners accept.

Response (200)JSON
{ "message": "Ownership accepted" }
POST/api/v1/tenant/nhis/:id/owners/:ownerId/decline

Decline an ownership assignment. NHI transitions to degraded management status.

Response (200)JSON
{ "message": "Ownership declined" }

Decommissioning

DELETE/api/v1/tenant/nhis/:id

Orchestrated decommission: revokes credentials, suspends bindings, performs impact analysis, transitions to revoked.

Request BodyJSON
{
  "dry_run": true
}
Response (dry_run: true)JSON
{
  "dry_run": true,
  "would_decommission": true,
  "impact": {
    "nhiId": "nhi-uuid",
    "directDependents": [...],
    "hardDependencyCount": 2,
    "riskLevel": "high"
  }
}
Response (dry_run: false)JSON
{
  "message": "NHI decommission initiated",
  "impact": { "directDependents": [...], "hardDependencyCount": 2, "riskLevel": "high" }
}

Dormancy Report

GET/api/v1/tenant/nhis/dormancy

Count NHIs by dormancy tier: idle (30-90d), dormant (90-180d), derelict (180d+).

Response (200)JSON
{
  "dormancy": {
    "idle": 12,
    "dormant": 4,
    "derelict": 1
  }
}

Estate Health

GET/api/v1/tenant/nhis/estate-health

Full estate summary: state distribution, management status breakdown, dormancy counts.

Response (200)JSON
{
  "byState": { "active": 85, "provisioned": 3, "pending_attestation": 7, "revoked": 2 },
  "byManagementStatus": { "healthy": 80, "degraded": 8, "unmanaged": 2, "pending_acceptance": 5 },
  "dormancy": { "idle": 12, "dormant": 4, "derelict": 1 }
}

Self-Repair Plans

GET/api/v1/tenant/nhis/repair-plans

View active self-repair assignments pending acceptance (generated by SCIM departure events).

Response (200)JSON
{
  "repairPlans": [
    {
      "nhi_id": "nhi-uuid",
      "nhi_name": "payment-processor-prod",
      "tier": 1,
      "role": "technical_owner",
      "assignee_id": "bob.senior",
      "assigned_at": "2026-07-28T09:00:00Z"
    }
  ]
}

Campaign Compliance Report

GET/api/v1/tenant/nhis/campaigns/:id/report

Full compliance report including unattested NHIs.

Response (200)JSON
{
  "progress": { "total": 42, "certified": 38, "revoked": 2, "pending": 2, "percentComplete": 95.2 },
  "unattested": [
    { "id": "nhi-uuid", "name": "legacy-batch-job", "tier": 3, "environment": "production", "current_state": "pending_attestation" }
  ]
}

Dry-Run Support

All state-modifying operations support dry_run: true in the request body. When set, the operation is validated and impact-analyzed without executing. Supported on:

  • POST /nhis/:id/revoke — returns current state + impact analysis
  • POST /nhis/:id/mode — validates mode against type registry
  • DELETE /nhis/:id — returns full decommission impact

AuthZEN Integration

NHI authorization modes map directly to the OpenID AuthZEN 1.0 SARC model used by the broader AuthHub platform. When an NHI makes an authorization request, the PDP intercepts and validates the NHI state before evaluating permissions.

PDP Hot-Path Integration

The NHI PDP Interceptor runs before every SpiceDB evaluation for NHI subjects. It checks:

  1. NHI is not revoked (Redis key check, sub-ms)
  2. NHI state is active/pending_attestation/degraded (cached state)
  3. No critical anomalies (rate spike threshold)
  4. JIT token is valid (for dynamic_jit mode)

AuthZEN Subject Mapping

NHI ModeAuthZEN SubjectEvaluation Behaviour
standalonenhi:<nhiId>Direct SpiceDB lookup on NHI relations
impersonate_liveuser:<userId> (delegated)Evaluates as bound user + validates binding active
impersonate_snapshotnhi:<nhiId>Checks cached permission set (no live SpiceDB)
autonomousnhi:<nhiId>SpiceDB + Beyond Zero behavioural oversight
dynamic_jitnhi:<nhiId> + jit_tokenValidates JIT token in Redis, then caveated tuple check
offline_capabilitynhi:<nhiId>Pre-signed capability validated by local PDP (no network)

AuthZEN Evaluation Example (NHI Subject)

POST /authzen/v1/evaluationJSON
{
  "subject": { "type": "nhi", "id": "payment-processor-prod" },
  "action": { "name": "process_payment" },
  "resource": { "type": "payment_gateway", "id": "stripe-prod" },
  "context": {
    "nhi_mode": "standalone",
    "jit_token": null
  }
}
Response (NHI state valid)JSON
{ "decision": true }
Response (NHI revoked)JSON
{
  "decision": false,
  "context": {
    "reason": [{ "id": "nhi_revoked", "en": "NHI has been revoked" }]
  }
}
Response (JIT token expired)JSON
{
  "decision": false,
  "context": {
    "reason": [{ "id": "jit_token_expired_or_revoked", "en": "JIT token is no longer valid" }]
  }
}

Disaster Recovery Governance

Configure and validate how your NHIs behave during regional failover. DR governance ensures business continuity without compromising security posture.

Scope

These endpoints expose NHI-level DR governance only. Platform infrastructure DR (HSM replication, SpiceDB cluster health, database failover) is managed internally by AuthHub and not exposed to tenant admins.

DR Configuration Schema

Set via PATCH /api/v1/tenant/nhis/:id with the dr_config field:

dr_config schemaJSON
{
  "dr_config": {
    "failoverEnvironment": "dr",
    "failoverRegion": "uk-west-2",
    "drSecretProviderRef": "arn:aws:secretsmanager:eu-west-2:123456:secret:nhi-dr-keys",
    "drPermissions": "read_only",
    "failoverMode": "automatic",
    "rtoSeconds": 300,
    "rpoSeconds": 60,
    "drReplicaNhiId": null,
    "drDependencyOverrides": [
      {
        "productionTargetRef": "stripe-api-prod",
        "drTargetRef": "stripe-api-dr",
        "drTargetDisplayName": "Stripe API (DR endpoint)"
      }
    ],
    "anomalySuppressionWindow": null,
    "lastDrDrillAt": null,
    "lastDrDrillResult": null
  }
}
FieldTypeDescription
failoverEnvironmentstringTarget environment on failover (e.g., "dr", "uk-west-2-dr")
failoverRegionstring?Geographic region identifier
drSecretProviderRefstring?DR-specific credential provider (Vault path, AWS ARN, etc.)
drPermissionsenumfull | read_only | minimal — permission degradation in DR
failoverModeenumautomatic (system-triggered) | manual (requires admin action)
rtoSecondsnumber?Recovery Time Objective
rpoSecondsnumber?Recovery Point Objective
drReplicaNhiIdstring?ID of the DR replica NHI (populated by clone-to-dr)
drDependencyOverridesarray?Dependencies that differ in DR (maps prod → DR targets)
anomalySuppressionWindowobject?Active suppression window for planned DR tests

DR Readiness Report

GET/api/v1/tenant/nhis/dr-readiness

Assess DR readiness for all Tier 0-1 NHIs. Returns gap analysis.

Response (200)JSON
{
  "summary": { "total": 8, "ready": 5, "gaps": 3 },
  "nhis": [
    { "id": "...", "name": "payment-processor", "tier": 0, "environment": "production", "issues": [], "ready": true },
    { "id": "...", "name": "ai-summarizer", "tier": 1, "environment": "production", "issues": ["missing_dr_credentials"], "ready": false },
    { "id": "...", "name": "auth-gateway", "tier": 0, "environment": "production", "issues": ["missing_dr_config"], "ready": false }
  ]
}

Failover Simulation

POST/api/v1/tenant/nhis/:id/failover

Simulate (or execute) a DR failover. Defaults to dry_run=true for safety.

Request BodyJSON
{ "dry_run": true }
Response (dry_run)JSON
{
  "dry_run": true,
  "failoverReport": {
    "nhiId": "nhi-uuid",
    "name": "payment-processor",
    "tier": 0,
    "drConfig": { "failoverEnvironment": "dr", "drPermissions": "read_only", ... },
    "readyForFailover": false,
    "issues": ["no_dr_credentials"],
    "impact": { "directDependents": [...], "hardDependencyCount": 2, "riskLevel": "high" },
    "brokenDependenciesInDr": 1,
    "brokenDependencies": [
      { "targetRef": "stripe-api-prod", "displayName": "Stripe API", "type": "hard" }
    ]
  }
}

Safety: Defaults to dry_run: true. Set dry_run: false to record an actual DR drill (updates lastDrDrillAt and lastDrDrillResult).

Clone to DR

POST/api/v1/tenant/nhis/:id/clone-to-dr

Create a DR replica of a production NHI. Links source → replica via dependency graph.

Response (201)JSON
{
  "source": { "id": "prod-nhi-uuid", "name": "payment-processor" },
  "drReplica": {
    "id": "dr-nhi-uuid",
    "name": "payment-processor-dr",
    "environment": "dr",
    "currentState": "provisioned",
    "tier": 0
  }
}

DR Strategy: Clone vs. Transition
AuthHub uses the clone strategy: a separate NHI record is created with environment: "dr"and linked to the source via the dependency graph. This preserves full audit trails for both production and DR instances independently. The source NHI's dr_config.drReplicaNhiId is auto-populated.

Anomaly Suppression (DR Test Window)

POST/api/v1/tenant/nhis/dr-suppression

Register a planned DR test window. Beyond Zero anomaly detection is suppressed for listed NHIs during the window.

Request BodyJSON
{
  "nhiIds": ["nhi-uuid-1", "nhi-uuid-2", "nhi-uuid-3"],
  "start": "2026-08-15T02:00:00Z",
  "end": "2026-08-15T04:00:00Z",
  "reason": "Planned quarterly DR drill — failover to uk-west-2"
}
Response (200)JSON
{
  "message": "DR anomaly suppression set for 3 NHIs",
  "window": {
    "start": "2026-08-15T02:00:00Z",
    "end": "2026-08-15T04:00:00Z",
    "reason": "Planned quarterly DR drill — failover to uk-west-2",
    "approvedBy": "admin@nhs-trust.net"
  }
}

Why this matters: A DR failover causes mass IP changes, region shifts, and credential rotations that would normally trigger Beyond Zero anomaly detection (dormancy violation, rate spikes, credential sharing). Pre-registering the window prevents false-positive auto-degradation of your NHIs during planned exercises.

Type Registry

Tenant-configurable NHI type definitions. Ships with 7 presets that can be customized or extended. Validation on NHI creation checks actor type, subtype, allowed modes, and environments.

GET/api/v1/tenant/nhis/types

List all type definitions for the tenant (presets + custom).

Response (200)JSON
{
  "types": [
    {
      "actorType": "ai_agent",
      "displayName": "AI Agent",
      "description": "LLM-powered agents, MCP tools, and autonomous AI systems",
      "subtypes": ["llm_agent", "mcp_tool", "rag_pipeline", "autonomous_agent", "copilot"],
      "defaultTier": 1,
      "defaultAttestationWindowDays": 30,
      "allowedAuthorizationModes": ["dynamic_jit", "autonomous", "impersonate_live"],
      "allowedEnvironments": ["production", "staging", "development"],
      "requiredFields": [{ "field": "businessContext.purpose", "label": "Agent Purpose" }],
      "maxTtlDays": 365,
      "enabled": true,
      "isPreset": true
    }
  ]
}
POST/api/v1/tenant/nhis/types

Create a custom type definition.

Request BodyJSON
{
  "actorType": "clinical_decision_support",
  "displayName": "Clinical Decision Support System",
  "description": "CDSS providing clinical recommendations",
  "subtypes": ["diagnostic_aid", "prescribing_assistant", "pathway_recommender"],
  "defaultTier": 1,
  "defaultAttestationWindowDays": 30,
  "allowedAuthorizationModes": ["dynamic_jit", "impersonate_live"],
  "allowedEnvironments": ["production"],
  "requiredFields": [
    { "field": "businessContext.mhra_class", "label": "MHRA Device Classification" }
  ],
  "maxTtlDays": 365
}
PATCH/api/v1/tenant/nhis/types/:actorType

Update a type definition (works on both presets and custom types).

Request Body (disable a preset)JSON
{ "enabled": false }
Request Body (extend subtypes)JSON
{
  "subtypes": ["llm_agent", "mcp_tool", "rag_pipeline", "autonomous_agent", "copilot", "clinical_summarizer"]
}
DELETE/api/v1/tenant/nhis/types/:actorType

Delete a custom type. Presets cannot be deleted — disable them instead.

POST/api/v1/tenant/nhis/types/:actorType/reset

Reset a preset type to factory defaults.

Preset Types

TypeDefault TierAttestationAllowed Modes
service_account290 daysstandalone, autonomous, offline_capability
ai_agent130 daysdynamic_jit, autonomous, impersonate_live
ci_cd_pipeline2180 daysstandalone, dynamic_jit
iot_device160 daysstandalone, offline_capability
infrastructure090 daysstandalone, autonomous
external_integration290 daysstandalone, impersonate_snapshot
robotic_process260 daysimpersonate_live, impersonate_snapshot, standalone