Developer Documentation
Darwan Authorization API
Integrate role-based access control, attribute policies, and compliance workflows into any service. One API for authorization, audit, and regulatory readiness.
Concepts
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.
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/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:
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 expired
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" }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. |
admin scope. Use an API key with admin scope or sign in via the console.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" }
]
}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"
}
]
}Caching Guidance
Cache only RBAC-only decisions (no attributes, no policies).
Keep TTL short (60-120 seconds).
Invalidate on webhook events.
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). |
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.
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. |
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
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, endDate
Returns 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.
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.
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 |
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 |
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 |
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");Regulatory Readiness
Built for compliance from the ground up
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 into your services. Check the console or reach out for support.
A KaritKarma Limited platform