Skip to main content

What are Conditional Permissions?

Conditional permissions allow you to add dynamic rules to your access control using JSON Logic expressions. Instead of simple allow/deny, you can create permissions that evaluate based on:
  • Subject attributes (department, clearance level, role metadata)
  • Resource properties (owner, status, tags)
  • Request context (time, IP address, device type)
  • Custom business logic

Where Conditions Apply

Conditions can be added at multiple levels:
LevelInterfaceUse Case
Role-PermissionBedrockRolePermission.condition”Editors can only edit draft documents”
Scope OverrideBedrockScopeRolePermissionOverride.condition”In production, only during business hours”
Resource PolicyBedrockResourcePolicy.subjectCondition”Only finance team can access this report”
Resource PolicyBedrockResourcePolicy.contextCondition”Only from approved IP ranges”

JSON Logic Basics

JSON Logic uses a simple JSON structure to express conditions:
{ "operator": [arguments] }

Common Operators

OperatorDescriptionExample
==Equals{"==": [{"var": "subject.type"}, "admin"]}
!=Not equals{"!=": [{"var": "resource.status"}, "archived"]}
>, >=, <, <=Comparisons{">=": [{"var": "subject.level"}, 3]}
inValue in array{"in": [{"var": "subject.dept"}, ["finance", "accounting"]]}
andAll conditions true{"and": [cond1, cond2]}
orAny condition true{"or": [cond1, cond2]}
!Negation{"!": [condition]}
ifConditional{"if": [cond, then, else]}

The var Operator

Use var to access values from the evaluation context:
{"var": "subject.meta.department"}
{"var": "resource.tags.classification"}
{"var": "context.time.hour"}

Conditional Role-Permissions

Add conditions when assigning permissions to roles:
# Editors can only edit documents they own
curl -X POST 'https://api.example.com/role-permissions' \
  -H 'Content-Type: application/json' \
  -d '{
    "roleId": "role_editor",
    "permissionId": "perm_document_edit",
    "condition": {
      "==": [
        {"var": "subject.id"},
        {"var": "resource.ownerId"}
      ]
    }
  }'
# Managers can approve expenses under $10,000
curl -X POST 'https://api.example.com/role-permissions' \
  -d '{
    "roleId": "role_manager",
    "permissionId": "perm_expense_approve",
    "condition": {
      "<": [{"var": "resource.amount"}, 10000]
    }
  }'

Conditional Scope Overrides

Add conditions to scope-level overrides:
# In production, only allow writes during business hours
curl -X POST 'https://api.example.com/scope-overrides/role-permissions' \
  -d '{
    "childScopeId": "scope_production",
    "roleId": "role_developer",
    "permissionId": "perm_deploy",
    "state": "enabled",
    "condition": {
      "and": [
        {">=": [{"var": "context.time.hour"}, 9]},
        {"<=": [{"var": "context.time.hour"}, 17]},
        {"in": [{"var": "context.time.dayOfWeek"}, [1, 2, 3, 4, 5]]}
      ]
    }
  }'

Context Variables

The evaluation context provides these variables:

Subject Variables

VariableDescription
subject.idSubject ID
subject.typeSubject type (user, agent, service)
subject.externalIdExternal system ID
subject.meta.*Custom metadata fields

Resource Variables

VariableDescription
resource.idResource ID
resource.typeResource type
resource.ownerIdOwner subject ID
resource.ownerScopeIdOwner scope ID
resource.meta.*Custom metadata fields
resource.tags.*Tag assignments

Context Variables

VariableDescription
context.time.hourCurrent hour (0-23)
context.time.dayOfWeekDay of week (0=Sun, 6=Sat)
context.ipRequest IP address
context.*Any custom context you provide

Common Patterns

Department-Based Access

{
  "in": [
    {"var": "subject.meta.department"},
    {"var": "resource.tags.allowedDepartments"}
  ]
}

Clearance Level

{
  ">=": [
    {"var": "subject.meta.clearanceLevel"},
    {"var": "resource.meta.requiredClearance"}
  ]
}

Owner-Only Access

{
  "==": [
    {"var": "subject.id"},
    {"var": "resource.ownerId"}
  ]
}

Business Hours Only

{
  "and": [
    {">=": [{"var": "context.time.hour"}, 9]},
    {"<=": [{"var": "context.time.hour"}, 17]},
    {"!": {"in": [{"var": "context.time.dayOfWeek"}, [0, 6]]}}
  ]
}

IP Allowlist

{
  "in": [
    {"var": "context.ip"},
    ["192.168.1.0/24", "10.0.0.0/8"]
  ]
}

Combined Conditions

{
  "or": [
    {"==": [{"var": "subject.type"}, "admin"]},
    {
      "and": [
        {"==": [{"var": "subject.meta.department"}, "finance"]},
        {">=": [{"var": "subject.meta.level"}, 3]}
      ]
    }
  ]
}

Evaluation Behavior

When a permission has a condition:
  1. No condition → Permission always applies
  2. Condition evaluates to true → Permission applies
  3. Condition evaluates to false → Permission does not apply
  4. Condition errors → Permission does not apply (fail-closed)
// Evaluation with context
const decision = await bedrock.evaluate({
  actor: { subjectId: "subject_jane" },
  scopeId: "scope_production",
  action: "deploy",
  context: {
    time: { hour: 14, dayOfWeek: 3 },
    ip: "192.168.1.100"
  }
});

Debugging Conditions

The decision output includes condition evaluation details:
const decision = await bedrock.evaluate(input);

console.log(decision.matches);
// Shows which permissions matched and their conditions

console.log(decision.evaluatedContext);
// Shows the full context used for evaluation

console.log(decision.explanation);
// Human-readable explanation of the decision

Best Practices

Complex nested conditions are hard to debug. Break them into multiple permissions if needed.
Create test cases for all condition branches before deploying.
Structure your metadata with clear, consistent naming.
Add descriptions to permissions explaining what the condition does.
If a condition can’t be evaluated (missing data), access is denied by default.