Authdog

ABAC

Last updated Nov 9, 2026
View as Markdown

Attribute-based access control (ABAC) makes decisions based on attributes of the user, the resource, and the request context. Authdog evaluates Rego policies at the edge, in process, with no external policy server.

When to use ABAC

ABAC is the right choice when:

  • Access depends on data, not a fixed job title
  • Rules reference resource properties (amount, owner, department)
  • Context matters (time, IP, location)
  • You want to express complex conditions that would explode into hundreds of RBAC roles

Typical ABAC rules:

  • "Managers can approve expenses under $5,000 in their own department"
  • "Users can edit resources they own"
  • "Access only during business hours from approved IPs"
  • "Confidential documents require clearance level 3+"

Public API

ABAC policies are managed via the environment-scoped REST API at https://api.authdog.com/v1/tenants/{tenantId}/environments/{environmentId}, authenticated with a tenant or environment API secret.

Operation Endpoint Method
List policies /abac-policies GET
Create or update policy /abac-policies POST
Validate policy /abac-policies/validate POST
Delete policy /abac-policies/{policyId} DELETE

List policies

curl https://api.authdog.com/v1/tenants/{tenantId}/environments/{envId}/abac-policies \
  -H "Authorization: Bearer $AUTHDOG_API_SECRET"

Response:

{
  "policies": [
    {
      "id": "pol_abc123",
      "name": "Department approval",
      "slug": "dept-approval",
      "description": "Managers approve in their department",
      "regoSource": "package authdog.authz\n\ndefault allow = false\n\nallow {\n  input.action == \"approve\"\n  input.user.department == input.resource.department\n}",
      "enabled": true,
      "createdAt": "2026-01-15T10:00:00Z",
      "updatedAt": "2026-01-15T10:00:00Z"
    }
  ]
}

Create or update policy

Include id to update an existing policy.

curl -X POST https://api.authdog.com/v1/tenants/{tenantId}/environments/{envId}/abac-policies \
  -H "Authorization: Bearer $AUTHDOG_API_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Owner can edit",
    "slug": "owner-edit",
    "description": "Resource owners can edit their own resources",
    "regoSource": "package authdog.authz\n\ndefault allow = false\n\nallow {\n  input.action == \"edit\"\n  input.resource.owner == input.user.id\n}",
    "enabled": true
  }'

Response:

{
  "policy": {
    "id": "pol_def456",
    "name": "Owner can edit",
    "slug": "owner-edit",
    "enabled": true
  }
}

Validate policy

Stateless syntax and semantic validation. Nothing is persisted.

curl -X POST https://api.authdog.com/v1/tenants/{tenantId}/environments/{envId}/abac-policies/validate \
  -H "Authorization: Bearer $AUTHDOG_API_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "regoSource": "package authdog.authz\n\ndefault allow = false\n\nallow { input.action == \"read\" }",
    "slug": "read-policy"
  }'

Response:

{
  "valid": true
}

On error:

{
  "valid": false,
  "errors": [
    {"line": 3, "column": 1, "message": "unexpected token"}
  ]
}

Delete policy

curl -X DELETE https://api.authdog.com/v1/tenants/{tenantId}/environments/{envId}/abac-policies/{policyId} \
  -H "Authorization: Bearer $AUTHDOG_API_SECRET"

Policy input schema

Every policy receives an input object. Your application supplies resource, action, and custom context fields.

{
  "user": {
    "id": "user_abc123",
    "email": "[email protected]",
    "department": "engineering",
    "clearanceLevel": 2,
    "roles": ["editor"],
    "groups": ["engineering-team"],
    "metadata": {}
  },
  "resource": {
    "type": "expense",
    "id": "exp_456",
    "department": "engineering",
    "amount": 3500,
    "owner": "user_abc123",
    "metadata": {}
  },
  "action": "approve",
  "context": {
    "ip": "192.168.1.100",
    "timestamp": "2026-11-09T14:30:00Z",
    "userAgent": "Mozilla/5.0 ...",
    "environment": "production"
  }
}

User attributes

Populated from the authenticated session:

Attribute Type Description
id string User ID
email string Primary email
department string From user profile or IdP
clearanceLevel number Custom attribute
roles array RBAC roles (if also configured)
groups array Group memberships
metadata object Custom user metadata

Resource attributes

Supplied by your application in the check request:

Attribute Type Description
type string Resource type (expense, document, etc.)
id string Resource identifier
Custom fields any Your domain attributes (amount, owner, department)

Context attributes

Supplied by your application or inferred:

Attribute Type Description
ip string Client IP address
timestamp string ISO 8601 request time
userAgent string User agent header
environment string Authdog environment name

Making authorization checks

Use the AuthZEN decision API to evaluate policies.

curl -X POST https://api.authdog.com/access/v1/evaluation \
  -H "Authorization: Bearer $AUTHDOG_ENV_API_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "subject": {"type": "user", "id": "user_abc123"},
    "action": {"name": "approve"},
    "resource": {
      "type": "expense",
      "id": "exp_456",
      "properties": {
        "department": "engineering",
        "amount": 3500,
        "owner": "user_abc123"
      }
    },
    "context": {
      "ip": "192.168.1.100"
    }
  }'

Response:

{
  "decision": true
}

Example policies

Department-scoped approval

package authdog.authz

default allow = false

allow {
  input.action == "approve"
  input.user.department == input.resource.department
  input.resource.amount < 5000
}

Owner can edit

package authdog.authz

default allow = false

allow {
  input.action == "edit"
  input.resource.owner == input.user.id
}

Business hours only

package authdog.authz

default allow = false

allow {
  hour := time.clock(time.parse_rfc3339_ns(input.context.timestamp))[0]
  hour >= 9
  hour < 17
}

Clearance level check

package authdog.authz

default allow = false

allow {
  input.action == "view"
  input.resource.classification == "confidential"
  input.user.clearanceLevel >= 3
}

IP allowlist

package authdog.authz

default allow = false

allowed_networks = {"10.0.0.0/8", "192.168.0.0/16"}

allow {
  some network
  allowed_networks[network]
  net.cidr_contains(network, input.context.ip)
}

Combining multiple conditions

package authdog.authz

default allow = false

allow {
  input.action == "transfer"
  input.resource.amount < 10000
  input.user.department == "finance"
  is_business_hours
  is_approved_ip
}

is_business_hours {
  hour := time.clock(time.parse_rfc3339_ns(input.context.timestamp))[0]
  hour >= 9
  hour < 17
}

is_approved_ip {
  startswith(input.context.ip, "10.")
}

CLI usage

CLI support for ABAC commands is coming soon. For now, use the generic API command:

# List policies
authdog api GET /v1/tenants/{tenantId}/environments/{envId}/abac-policies

# Create policy
authdog api POST /v1/tenants/{tenantId}/environments/{envId}/abac-policies \
  --data '{"name":"My policy","slug":"my-policy","regoSource":"package authdog.authz\n\ndefault allow = false\n\nallow { input.action == \"read\" }","enabled":true}'

# Validate policy
authdog api POST /v1/tenants/{tenantId}/environments/{envId}/abac-policies/validate \
  --data '{"regoSource":"package authdog.authz\n\ndefault allow = false\n\nallow { true }","slug":"test"}'

# Delete policy
authdog api DELETE /v1/tenants/{tenantId}/environments/{envId}/abac-policies/{policyId}

Console

Authorization → ABAC (when ABAC model is selected):

  • Policies: list, create, edit, enable/disable
  • Policy Editor: Monaco editor with Rego syntax highlighting
  • Validation: real-time syntax checking