Skip to content
Darwan

Allow. Deny. Explain.

Darwan is KaritKarma's centralised authorization service. One service decides who may do what, returns the rule that made the call, and hashes the decision into a SHA-256 audit chain anyone with audit scope can re-verify. RBAC plus deny-override ABAC, 58 endpoints, 4 SDKs. Live at darwan.net.

58
/v1 endpoints
one .NET 10 service
4
First-party SDKs
.NET, Go, Node, Rust
SHA-256
Audit chain
verify endpoint + CSV
120s
Redis cache TTL
configurable per tenant
POST /v1/authorize
POST /v1/authorize
Authorization: Bearer <wenme-jwt>
{
  "tenantId": "dk_acme",
  "principalId": "usr_7f3a",
  "action": "read",
  "resourceType": "sales.order",
  "resourceId": "ord_4201",
  "subject": { "department": "sales" },
  "resource": { "owner": "usr_7f3a" }
}

<-- 200 OK
{
  "allowed": true,
  "decision": "allow",
  "policyVersion": "v3.2.1",
  "ruleId": "R014",
  "reason": "RBAC grant + ABAC owner match",
  "decisionId": "dec_8c2f..."
}

// audit event hash-chained
// GET /v1/audit-events/verify -> chain OK
Decision pipeline

Four steps. Deny by default. Explain every call.

Every request walks the same pipeline: bind, RBAC, ABAC, explain. No shortcuts, no bypass, no black-box deny.

Step 1

Bind principal to tenant

Wenme issues the JWT, Darwan resolves principal-role assignments inside the tenant scope, then walks group-inherited roles. Expired time-bound assignments drop out before any rule fires.

Step 2

RBAC grant required

The (action, resourceType) tuple is matched against the principal's effective role-permission set. No grant means deny. Attribute-free decisions are cached in Redis; the cache is bypassed when attribute bags, scoped roles, or a policy set are in play.

Step 3

ABAC policy overlay

Policy sets are versioned. Deny rules evaluate first, then allow rules with JSON conditions on subject, resource, and request context. Deny always overrides allow.

Step 4

Explain + audit chain

Every decision returns the outcome, reason, rule id, and policy version. The authorize:explain endpoint adds the matched rules and a decision id. The audit event is hashed into a per-tenant SHA-256 integrity chain that GET /v1/audit-events/verify re-checks end to end.

Comparison

Where Darwan sits in the authorization landscape.

FeatureDarwanOPACasbinKeycloak
Multi-tenant by designEvery resource scoped by tenantId, isolation at the schemaSingle-policy bundle, multi-tenancy is bring-your-ownSingle enforcer, tenant routing in app codeRealm per tenant, separate admin surfaces
RBAC plus ABAC overlayRBAC grant required, then ABAC policy can denyPure ABAC, RBAC modelled on topModel-string per pattern, no first-class layeringRBAC core, optional policy add-on
Explainable decisionsauthorize:explain returns matched rules, reasons, decision idDecision logs with input replayBoolean only, no native traceToken introspection, no per-decision trace
Signed audit chainPer-tenant SHA-256 chain, verify endpoint + CSV exportExternal SIEM responsibilityAdapter-dependentStandard event log, no integrity chain
Deployment modelSelf-host or KaritKarma-managed in-regionSidecar per service, you operate everythingLibrary, embedded in app processSelf-host, JVM operations
SDKs

Four first-party clients.

C# / .NET
First-party. Mirrors the .NET 10 server contract one-to-one.
Go
Idiomatic Go client. Callers pass action and resourceType directly.
Node.js
Hand-written TypeScript client, published as @darwan/sdk.
Rust
reqwest + serde client for service-to-service authorization.
Integrations

Darwan is the policy spine of the KaritKarma stack.

Wenme

Issues the OAuth 2.1 JWT Darwan validates against its userinfo endpoint

BitsPath

159 Darwan permissions across 17 categories, 63 of them pbx.*

BitsPath Voice

Pure-Rust voice engine calls Darwan on every authorized API action

Your runtime

Anything that can POST JSON: dk_ API keys or Wenme bearer tokens, four SDKs, OpenAPI document

Stack

.NET 10, Postgres, Redis.

Authorization service
.NET 10, C# 13, PostgreSQL 18.4, Redis 8
SDKs
.NET, Go, Node.js, Rust (first-party, all four)
Audit
SHA-256 hash chain per tenant, verify endpoint, CSV export
Observability
Prometheus metrics, OpenAPI document, per-tenant scoping
Frequently asked

Questions buyers actually ask.

What is Darwan?
Darwan is KaritKarma's centralised authorization service for regulated institutions. It answers a single question on every request: is this principal allowed to perform this action on this resource inside this tenant? Authentication is handled by Wenme (OAuth 2.1 with PKCE), and Darwan layers RBAC plus deny-override ABAC, explainable decisions, and a SHA-256 audit chain on top.
How does Darwan compare to Open Policy Agent?
OPA is a general policy engine deployed as a sidecar per service, with multi-tenancy and RBAC modelled in Rego by the application team. Darwan is opinionated for SaaS and regulated workloads: tenant isolation is first-class, RBAC and ABAC are layered with a deny-override rule, and a signed audit chain is built in. You operate one Darwan, not one OPA per service.
Does Darwan support attribute-based policies?
Yes. Policy sets are versioned, and each rule carries a JSON condition that runs against subject, resource, and request context. A typical use is restricting an invoice.read grant so a non-owner cannot read another department's invoice. Deny rules evaluate first, then allow rules. Deny always overrides allow.
Where does Darwan fit relative to Wenme?
Wenme answers who you are. Darwan answers what you may do. A request arrives with a Wenme-issued JWT, the calling service forwards the token (or trusted principal headers) to Darwan, and Darwan returns allow or deny with a reason. The two services are independent and can be deployed separately.
What is the API contract for /v1/authorize?
Authorize uses a split shape: action plus resourceType, not a flat permissionKey. For a permission string such as sales.order.read, the caller passes action=read and resourceType=sales.order. The body also carries tenantId, principalId, optional resourceId, and subject/resource/context attribute bags for ABAC evaluation. The response returns allowed, decision, policyVersion, ruleId, and reason.
How does Darwan make its audit log tamper-evident?
Every audit event is SHA-256 hash-chained per tenant: the previous event's hash is folded into the next, so any edit or deletion breaks the chain. A dedicated endpoint, GET /v1/audit-events/verify, re-computes the whole chain on demand, and audit events export as CSV or JSON for evidence packs. Retention is configurable with a background archival service.

One service, one decision, one signature.

A 45-minute session with the engineer who will be responsible for your deployment. We map your audit findings to specific platform controls.