Authdog

ABAC

Last updated Nov 9, 2026
View as Markdown

Attribute-based access control (ABAC) evaluates policies against attributes of the user, the resource, and the request context. This quickstart walks through setting up ABAC with Rego policies.

Prerequisites

  • An Authdog account with at least one tenant and environment
  • Familiarity with basic Rego syntax (Open Policy Agent's language)

When to use ABAC

ABAC shines when access decisions depend on data that doesn't fit cleanly into roles:

  • "Managers can approve expenses under $5,000 in their own department"
  • "Users can edit resources they own"
  • "Access is allowed only during business hours from approved IP ranges"
  • "Documents marked 'confidential' are visible only to users with clearance level 3+"

1. Enable ABAC for the environment

Console: Authorization → Model → select ABAC

The environment now evaluates Rego policies instead of checking role assignments.

2. Create your first policy

Policies are written in Rego and evaluated at the edge. The policy receives input with the user, resource, action, and context.

Console: Authorization → Policies → Create Policy

Example policy — department-scoped approval:

package authdog.authz

default allow = false

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

API:

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": "Department approval policy",
    "slug": "dept-approval",
    "regoSource": "package authdog.authz\n\ndefault allow = false\n\nallow {\n  input.action == \"approve\"\n  input.user.department == input.resource.department\n  input.resource.amount < 5000\n}",
    "enabled": true
  }'

3. Validate the policy

Before enabling a policy, validate its syntax.

API:

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"
  }'
# → {"valid": true}

4. Understand the input schema

Every policy receives an input object with:

{
  "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"
  }
}

Your application supplies resource, action, and any custom context fields when making a check request.

5. Check authorization in your app

SDK (Node.js):

import { Authdog } from "@authdog/node"

const authdog = new Authdog({ apiSecret: process.env.AUTHDOG_API_SECRET })

app.post("/expenses/:id/approve", requireAuth, async (req, res) => {
  const expense = await getExpense(req.params.id)
  
  const allowed = await authdog.abac.check({
    userId: req.user.id,
    action: "approve",
    resource: {
      type: "expense",
      id: expense.id,
      department: expense.department,
      amount: expense.amount,
    },
    context: {
      ip: req.ip,
    },
  })
  
  if (!allowed) {
    return res.status(403).json({ error: "Not authorized to approve this expense" })
  }
  
  await approveExpense(expense.id)
  res.json({ approved: true })
})

REST API via AuthZEN:

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
      }
    }
  }'
# → {"decision": true}

Example policies

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)
}

6. List and manage policies

List policies:

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

Delete a policy:

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

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 a policy
authdog api POST /v1/tenants/{tenantId}/environments/{envId}/abac-policies \
  --data '{"name":"Owner edit","slug":"owner-edit","regoSource":"package authdog.authz\n\ndefault allow = false\n\nallow { input.action == \"edit\"; input.resource.owner == input.user.id }","enabled":true}'

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

Next steps