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.
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: Bearer dk_live_a1b2c3d4.e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4
Content-Type: application/jsondk_— fixed prefixliveortest— environmenta1b2c3d4— 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:
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
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 expiredSecurity
POST /v1/api-keys/{id}/rotate) to replace keys without downtime.Getting Started
Quick start
Create tenant & roles
Use the admin console or API to create a tenant, define roles, and assign permissions.
Assign roles
Assign roles to principals or groups. Optionally set expiry dates and SoD constraints.
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:
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"
}'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"
}'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"
}'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"
}'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"
}'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
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
{
"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
[
{
"id": "00000000-0000-0000-0000-000000000001",
"name": "Acme Corp",
"planTier": "pro",
"status": "Active"
}
]Deactivate a tenant
{
"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.
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | Yes | Unique tenant name |
| planTier | string | No | Plan tier: free, starter, pro, enterprise. Defaults to free. |
| id | Guid | No | Optional custom UUID. Auto-generated if omitted. |
Note
admin scope. Use an API key with admin scope or sign in via the console.Authorization
Explainable checks
Call POST /v1/authorize:explain to get full decision metadata for debugging and compliance evidence.
{
"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.
{
"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
Assignments
Role assignments
Assign roles to principals directly or through groups.
{
"tenantId": "...",
"principalId": "...",
"roleId": "...",
"expiresAt": "2026-06-01T00:00:00Z"
}{
"tenantId": "...",
"groupId": "...",
"roleId": "...",
"expiresAt": null
}| Field | Type | Required | Description |
|---|---|---|---|
| tenantId | Guid | Yes | Tenant scope |
| principalId / groupId | Guid | Yes | Target principal or group |
| roleId | Guid | Yes | Role to assign |
| expiresAt | DateTimeOffset? | No | Auto-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
{
"tenantId": "...",
"name": "Finance SoD",
"description": "Approver and Requester cannot be the same person",
"conflictingRoleIds": ["<role-a-id>", "<role-b-id>"],
"enforcement": "block"
}| Enforcement | Behavior |
|---|---|
| block | Returns 409 Conflict with violation details. Assignment is rejected. |
| warn | Assignment proceeds. Warning included in response body. |
Note
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
{
"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
{
"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
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-events?tenantId=...&page=1&pageSize=50
Optional filters:
principalId, action, resourceType,
decision (allow/deny),
startDate, endDateReturns paginated response: items, page, pageSize, totalCount, totalPages.
Summary
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/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
Integration
API key scopes
When creating API keys, scope access to specific capabilities:
| Scope | Access |
|---|---|
| authorize | Call authorization endpoints |
| assignments:read / :write | View and manage role assignments |
| audit:read / audit:export | Query and export audit events |
| compliance:read / :write | Manage SoD constraints and access reviews |
| admin | Full access to all endpoints |
Integration
Webhooks
Subscribe to events to sync caches and downstream systems in real-time.
| Event | Trigger |
|---|---|
| role.created | New role created |
| permission.created | New permission created |
| assignment.principal_role.created | Role assigned to principal |
| assignment.role_permission.created | Permission linked to role |
| sod_constraint.created | New SoD constraint created |
| access_review.created | New access review campaign started |
| access_review.item_decided | Review item approved or revoked |
| access_review.completed | All items decided, review finalized |
Integration
Endpoint reference
Complete list of API endpoints grouped by domain.
Tenants
| Method | Endpoint | Description | Scope |
|---|---|---|---|
| POST | /v1/tenants | Create tenant | admin |
| GET | /v1/tenants | List all tenants | admin |
| DELETE | /v1/tenants/{id} | Deactivate tenant | admin |
Authorization
| Method | Endpoint | Description | Scope |
|---|---|---|---|
| POST | /v1/authorize | Evaluate authorization | authorize |
| POST | /v1/authorize:explain | Explainable decision | authorize |
| POST | /v1/authorize/batch | Batch authorization | authorize |
Assignments
| Method | Endpoint | Description | Scope |
|---|---|---|---|
| POST | /v1/assignments/principal-role | Assign role to principal | assignments:write |
| GET | /v1/assignments/principal-role | List principal-role assignments | assignments:read |
| POST | /v1/assignments/group-role | Assign role to group | assignments:write |
| GET | /v1/assignments/group-role | List group-role assignments | assignments:read |
Compliance
| Method | Endpoint | Description | Scope |
|---|---|---|---|
| POST | /v1/sod-constraints | Create SoD constraint | compliance:write |
| GET | /v1/sod-constraints | List SoD constraints | compliance:read |
| DELETE | /v1/sod-constraints/{id} | Delete SoD constraint | compliance:write |
| POST | /v1/access-reviews | Create access review | compliance:write |
| GET | /v1/access-reviews | List access reviews | compliance:read |
| GET | /v1/access-reviews/{id} | Get review with items | compliance:read |
| POST | /v1/access-reviews/{id}/items/{itemId}/decide | Approve or revoke item | compliance:write |
| POST | /v1/access-reviews/{id}/complete | Complete review | compliance:write |
Audit
| Method | Endpoint | Description | Scope |
|---|---|---|---|
| GET | /v1/audit-events | Paginated audit log query | audit:read |
| GET | /v1/audit-events/summary | Event count summary | audit:read |
| GET | /v1/audit-events/export | CSV/JSON export | audit:export |
| GET | /v1/audit-events/verify | Hash chain verification | audit:read |
Integration
SDK quick starts
Official SDKs for your stack. Authorize with a single function call.
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.