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

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

Response:

```json
{
  "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.

```bash
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:

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

### Validate policy

Stateless syntax and semantic validation. Nothing is persisted.

```bash
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:

```json
{
  "valid": true
}
```

On error:

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

### Delete policy

```bash
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.

```json
{
  "user": {
    "id": "user_abc123",
    "email": "jane@example.com",
    "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.

```bash
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:

```json
{
  "decision": true
}
```

## Example policies

### Department-scoped approval

```rego
package authdog.authz

default allow = false

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

### Owner can edit

```rego
package authdog.authz

default allow = false

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

### Business hours only

```rego
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

```rego
package authdog.authz

default allow = false

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

### IP allowlist

```rego
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

```rego
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:

```bash
# 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

## Related

- [Authorization concepts](/docs/concepts/authorization) — compare ABAC with RBAC and FGA
- [ABAC quickstart](/docs/quickstarts/abac) — step-by-step setup
- [AuthZEN API](/docs/authzen) — vendor-neutral decision endpoint
- [Rego language reference](https://www.openpolicyagent.org/docs/latest/policy-language/) — full Rego documentation
