Skip to content
DarwanDarwan

Specification · v1

RBAC, ABAC, and compliance — one authorization API.

Darwan is the authorization service behind KaritKarma's platform. Role-based access control, attribute policies, separation-of-duties, and immutable audit trails — integrated into any service through a single HTTPS endpoint.

RBACABACMulti-TenantSOX / SOC 2ISO 27001HIPAA

Getting Started

Concepts

Every Darwan request is scoped to a tenant and a principal. Roles grant permissions; attribute rules narrow or extend those grants; separation of duties blocks toxic combinations; and every decision is logged with a tamper-evident hash chain.

Tenant

Isolation boundary. Every request includes tenantId.

Principal

User or service identity. Every request includes principalId.

Permission Key

Format: domain.resourceType.action (e.g. erp.invoice.read).

RBAC + ABAC

Roles grant permissions; ABAC rules refine; deny overrides allow.

Time-Bound

Role grants can expire automatically via expiresAt.

SoD Constraints

Conflicting roles are blocked or warned at assignment time.

Access Reviews

Periodic certification campaigns to approve or revoke assignments.

Audit Immutability

Every decision is SHA-256 hash-chained with per-tenant sequencing.

Getting Started

Authentication

All API requests require a Darwan API key passed as a bearer token. OAuth is only used for the admin UI login — not for API calls.

API key format

Authorization headerhttp
Authorization: Bearer dk_live_a1b2c3d4.e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4
Content-Type: application/json
  • dk_ — fixed prefix
  • live or test — environment
  • a1b2c3d4 — 8-character key ID
  • .e5f6... — 32-character secret (after the dot)

Create an API key

Create API keys via the admin UI at darwan.net/dashboard or via the API:

Create API keybash
curl -X POST https://darwan.net/v1/api-keys \
  -H "Authorization: Bearer dk_live_YOUR_ADMIN_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "tenantId": "YOUR_TENANT_ID",
    "name": "My Service Key",
    "environment": "live",
    "scopes": ["authorize", "roles:write", "permissions:write", "assignments:write"]
  }'

Quick smoke test

Verify your key worksbash
curl -H "Authorization: Bearer dk_live_YOUR_KEY" https://darwan.net/v1/tenants

# 200 = key works with admin scope
# 403 = key works but lacks admin scope
# 401 = key is invalid, revoked, or expired

Security

API keys are shown only once at creation time. Store them securely. Use rotation ( POST /v1/api-keys/{id}/rotate) to replace keys without downtime.

Getting Started

Quick start

STEP 01

Create tenant & roles

Use the admin console or API to create a tenant, define roles, and assign permissions.

STEP 02

Assign roles

Assign roles to principals or groups. Optionally set expiry dates and SoD constraints.

STEP 03

Authorize

Call POST /v1/authorize from your service. Get an allow/deny decision with audit trail.

Full working example

Given a tenant ID and API key, here is the exact sequence to set up roles and permissions:

Step 1 — Create a rolebash
curl -X POST https://darwan.net/v1/roles \
  -H "Authorization: Bearer dk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "tenantId": "YOUR_TENANT_ID",
    "name": "editor",
    "description": "Can read and write articles"
  }'
Step 2 — Create a permissionbash
curl -X POST https://darwan.net/v1/permissions \
  -H "Authorization: Bearer dk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "tenantId": "YOUR_TENANT_ID",
    "name": "article.write",
    "description": "Write articles",
    "resourceType": "article",
    "action": "write"
  }'
Step 3 — Assign permission to rolebash
curl -X POST https://darwan.net/v1/assignments/role-permission \
  -H "Authorization: Bearer dk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "tenantId": "YOUR_TENANT_ID",
    "roleId": "ROLE_ID_FROM_STEP_1",
    "permissionId": "PERMISSION_ID_FROM_STEP_2"
  }'
Step 4 — Create a principalbash
curl -X POST https://darwan.net/v1/principals \
  -H "Authorization: Bearer dk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "tenantId": "YOUR_TENANT_ID",
    "externalId": "user-123",
    "displayName": "John Doe"
  }'
Step 5 — Assign role to principalbash
curl -X POST https://darwan.net/v1/assignments/principal-role \
  -H "Authorization: Bearer dk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "tenantId": "YOUR_TENANT_ID",
    "principalId": "PRINCIPAL_ID_FROM_STEP_4",
    "roleId": "ROLE_ID_FROM_STEP_1"
  }'
Step 6 — Authorizebash
curl -X POST https://darwan.net/v1/authorize \
  -H "Authorization: Bearer dk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "tenantId": "YOUR_TENANT_ID",
    "principalId": "PRINCIPAL_ID_FROM_STEP_4",
    "action": "write",
    "resourceType": "article"
  }'

# Response: { "decision": "allow" }

Security

Order matters: tenant must exist first, then roles and permissions, then assign permissions to roles, then create principals, then assign roles to principals. Only then can you authorize.

Getting Started

Tenant management

Tenants are the top-level isolation boundary. Every resource (roles, permissions, assignments, API keys) belongs to a tenant. Use the admin console or API to create and manage tenants.

Create a tenant

POST /v1/tenantsjson
{
  "name": "Acme Corp",
  "planTier": "pro"
}

Returns the created tenant with its generated id. You can optionally pass an id field to use a specific UUID.

List tenants

GET /v1/tenantsjson
[
  {
    "id": "00000000-0000-0000-0000-000000000001",
    "name": "Acme Corp",
    "planTier": "pro",
    "status": "Active"
  }
]

Deactivate a tenant

DELETE /v1/tenants/{id}json
{
  "id": "00000000-0000-0000-0000-000000000001",
  "name": "Acme Corp",
  "planTier": "pro",
  "status": "Suspended"
}

Soft-deletes the tenant by setting status to Suspended. Associated resources become inaccessible but are not deleted.

FieldTypeRequiredDescription
namestringYesUnique tenant name
planTierstringNoPlan tier: free, starter, pro, enterprise. Defaults to free.
idGuidNoOptional custom UUID. Auto-generated if omitted.

Note

All tenant endpoints require the admin scope. Use an API key with admin scope or sign in via the console.

Authorization

Authorization request

Call POST /v1/authorize with the principal, action, and resource. Darwan evaluates RBAC grants, ABAC policies, time-bound assignments, and returns a decision.

Request bodyjson
{
  "tenantId": "00000000-0000-0000-0000-000000000001",
  "principalId": "00000000-0000-0000-0000-000000000010",
  "action": "read",
  "resourceType": "invoice",
  "resourceId": "inv-001",
  "subject": { "team": "finance" },
  "resource": { "owner_id": "user-1" },
  "context": { "ip": "127.0.0.1" }
}
Response (allowed)json
{
  "allowed": true,
  "decision": "allow",
  "reason": "RBAC grant matched"
}

Authorization

Explainable checks

Call POST /v1/authorize:explain to get full decision metadata for debugging and compliance evidence.

Responsejson
{
  "allowed": true,
  "decision": "allow",
  "decisionId": "d-001",
  "policyVersion": 3,
  "reasons": ["Principal has role 'finance-viewer'"],
  "matchedRules": [
    { "ruleId": "r-1", "effect": "allow", "source": "rbac" }
  ]
}

Authorization

Batch checks

Use POST /v1/authorize/batch to evaluate multiple authorization checks in a single request, reducing network round-trips.

Request bodyjson
{
  "items": [
    {
      "requestId": "req-1",
      "tenantId": "...",
      "principalId": "...",
      "action": "read",
      "resourceType": "invoice"
    },
    {
      "requestId": "req-2",
      "tenantId": "...",
      "principalId": "...",
      "action": "write",
      "resourceType": "invoice"
    }
  ]
}

Authorization

Caching guidance

  • Cache only RBAC-only decisions (no attributes, no policies).
  • Keep TTL short (60–120 seconds).
  • Invalidate on webhook events.

Important

Do not cache decisions that involve ABAC attributes or time-sensitive context. These can change between requests.

Assignments

Role assignments

Assign roles to principals directly or through groups.

POST /v1/assignments/principal-rolejson
{
  "tenantId": "...",
  "principalId": "...",
  "roleId": "...",
  "expiresAt": "2026-06-01T00:00:00Z"
}
POST /v1/assignments/group-rolejson
{
  "tenantId": "...",
  "groupId": "...",
  "roleId": "...",
  "expiresAt": null
}
FieldTypeRequiredDescription
tenantIdGuidYesTenant scope
principalId / groupIdGuidYesTarget principal or group
roleIdGuidYesRole to assign
expiresAtDateTimeOffset?NoAuto-expire date. Past dates rejected (400).

Assignments

Time-bound assignments

Role assignments can have an optional expiresAt field. Expired assignments are automatically excluded from authorization and cleaned up.

Auto-filtered

Authorization checks apply: ExpiresAt == null || ExpiresAt > UtcNow

Background cleanup

AssignmentExpiryService runs every 5 minutes to delete expired rows.

Past date rejected

Setting expiresAt to a past date returns 400 Bad Request.

Permanent by default

Omit expiresAt or pass null for assignments that never expire.

Compliance

Separation of duties (SoD)

SoD constraints prevent conflicting roles from being assigned to the same principal. Required by SOX, PCI DSS, and NIST 800-53.

Create a constraint

POST /v1/sod-constraintsjson
{
  "tenantId": "...",
  "name": "Finance SoD",
  "description": "Approver and Requester cannot be the same person",
  "conflictingRoleIds": ["<role-a-id>", "<role-b-id>"],
  "enforcement": "block"
}
EnforcementBehavior
blockReturns 409 Conflict with violation details. Assignment is rejected.
warnAssignment proceeds. Warning included in response body.

Note

SoD validation checks both direct principal-role assignments and indirect group-role paths. Group-role assignments check all principals in the group.

Compliance

Access reviews

Periodic access reviews let you certify that all role assignments are still appropriate. Required by SOX, SOC 2, ISO 27001, and PCI DSS.

Create a review

POST /v1/access-reviewsjson
{
  "tenantId": "...",
  "name": "Q1 2026 Review",
  "reviewerPrincipalId": "...",
  "dueDate": "2026-03-31T23:59:59Z",
  "includeGroupRoles": true
}

Creates a review with status pending. Generates one item per current role assignment. Set includeGroupRoles: true to also review group-role assignments.

Decide items

POST /v1/access-reviews/{id}/items/{itemId}/decidejson
{
  "decision": "approved",
  "reviewedByPrincipalId": "...",
  "notes": "Verified with manager"
}
  • approved — assignment is retained.
  • revoked — the underlying role assignment is deleted immediately.

Complete review

Call POST /v1/access-reviews/{id}/complete. Returns 409 if pending items remain. Sets status to completed.

Auto-expiry

Note

The AccessReviewReminderService runs every 6 hours. Overdue reviews (past dueDate and still pending or in-progress) are automatically set to expired.

Compliance

Audit events

Every authorization decision is logged as an audit event. Query, summarize, and export audit data for compliance reporting.

Query

GET /v1/audit-eventshttp
GET /v1/audit-events?tenantId=...&page=1&pageSize=50

Optional filters:
  principalId, action, resourceType,
  decision (allow/deny),
  startDate, endDate

Returns paginated response: items, page, pageSize, totalCount, totalPages.

Summary

GET /v1/audit-events/summaryhttp
GET /v1/audit-events/summary?tenantId=...&period=30d

Response:
{
  "total": 12450,
  "allowCount": 11200,
  "denyCount": 1250,
  "period": "30d"
}

Periods: 7d, 30d, 90d.

Export

GET /v1/audit-events/export?tenantId=...&format=csv

  • csv — returns Content-Type: text/csv with header row.
  • json — returns an array of audit event objects.
  • Maximum 10,000 events per export. Same filters as query.

Compliance

Audit integrity

Every audit event is assigned a per-tenant sequence number and a SHA-256 hash that chains to the previous event. This makes tampering detectable.

GET /v1/audit-events/verifyhttp
GET /v1/audit-events/verify?tenantId=...&startSequence=1&limit=1000

Response:
{
  "verified": true,
  "checkedCount": 1000,
  "firstInvalidSequence": null,
  "message": "Chain intact"
}

verified: true

The hash chain is intact. No tampering detected.

verified: false

Returns the sequence number of the first tampered event.

Security

Old audit events are archived (copied to AuditArchives) rather than deleted. The hash chain remains verifiable through the archive.

Integration

API key scopes

When creating API keys, scope access to specific capabilities:

ScopeAccess
authorizeCall authorization endpoints
assignments:read / :writeView and manage role assignments
audit:read / audit:exportQuery and export audit events
compliance:read / :writeManage SoD constraints and access reviews
adminFull access to all endpoints

Integration

Webhooks

Subscribe to events to sync caches and downstream systems in real-time.

EventTrigger
role.createdNew role created
permission.createdNew permission created
assignment.principal_role.createdRole assigned to principal
assignment.role_permission.createdPermission linked to role
sod_constraint.createdNew SoD constraint created
access_review.createdNew access review campaign started
access_review.item_decidedReview item approved or revoked
access_review.completedAll items decided, review finalized

Integration

Endpoint reference

Complete list of API endpoints grouped by domain.

Tenants

MethodEndpointDescriptionScope
POST/v1/tenantsCreate tenantadmin
GET/v1/tenantsList all tenantsadmin
DELETE/v1/tenants/{id}Deactivate tenantadmin

Authorization

MethodEndpointDescriptionScope
POST/v1/authorizeEvaluate authorizationauthorize
POST/v1/authorize:explainExplainable decisionauthorize
POST/v1/authorize/batchBatch authorizationauthorize

Assignments

MethodEndpointDescriptionScope
POST/v1/assignments/principal-roleAssign role to principalassignments:write
GET/v1/assignments/principal-roleList principal-role assignmentsassignments:read
POST/v1/assignments/group-roleAssign role to groupassignments:write
GET/v1/assignments/group-roleList group-role assignmentsassignments:read

Compliance

MethodEndpointDescriptionScope
POST/v1/sod-constraintsCreate SoD constraintcompliance:write
GET/v1/sod-constraintsList SoD constraintscompliance:read
DELETE/v1/sod-constraints/{id}Delete SoD constraintcompliance:write
POST/v1/access-reviewsCreate access reviewcompliance:write
GET/v1/access-reviewsList access reviewscompliance:read
GET/v1/access-reviews/{id}Get review with itemscompliance:read
POST/v1/access-reviews/{id}/items/{itemId}/decideApprove or revoke itemcompliance:write
POST/v1/access-reviews/{id}/completeComplete reviewcompliance:write

Audit

MethodEndpointDescriptionScope
GET/v1/audit-eventsPaginated audit log queryaudit:read
GET/v1/audit-events/summaryEvent count summaryaudit:read
GET/v1/audit-events/exportCSV/JSON exportaudit:export
GET/v1/audit-events/verifyHash chain verificationaudit:read

Integration

SDK quick starts

Official SDKs for your stack. Authorize with a single function call.

C#csharp
var client = new Darwan.Sdk.DarwanClient(
    new HttpClient { BaseAddress = new Uri("https://darwan.net") });

var decision = await client.AuthorizeAsync(new AuthorizeRequest
{
    TenantId = Guid.Parse("..."),
    PrincipalId = Guid.Parse("..."),
    Action = "read",
    ResourceType = "invoice"
});

if (decision.Allowed)
    Console.WriteLine("Access granted");

Integration

Compliance readiness

Darwan maps directly to the controls required by the frameworks your auditors ask about.

SOX

  • SoD constraints
  • Access reviews
  • Immutable audit logs

SOC 2

  • Audit trails
  • Access reviews
  • Time-bound access
  • Integrity verification

ISO 27001

  • RBAC
  • Periodic reviews
  • Audit logging
  • Least privilege

HIPAA

  • Access controls
  • Audit logs
  • Session expiry
  • Review certification

PCI DSS

  • Role-based access
  • SoD
  • Quarterly reviews
  • Audit retention

GDPR

  • Access control
  • Audit trails
  • Data minimization
  • Review evidence

NIST 800-53

  • RBAC/ABAC
  • SoD
  • Continuous monitoring
  • Audit integrity

Need help?

Our team is here to help you integrate Darwan. Check the console or reach out for support.

A KaritKarma Limited platform.

© 2026 Darwan. All rights reserved.