Skip to main content

PORC Expressions

A PORC Expression is the normalized input format for policy evaluation. PORC stands for:

PORC Expression

Overview

PORC is the universal language for expressing authorization requests in the PolicyEngine. Every policy evaluation receives a PORC expression as input, regardless of the origin of the request. This standardized format makes it possible to:

  • Write policies that work across different enforcement points
  • Reuse policy logic regardless of the original request format
  • Create consistent audit trails
  • Decouple policy logic from application-specific request formats

PORC Structure

{
"principal": {
"sub": "user@example.com",
"mroles": ["mrn:iam:role:admin"],
"mgroups": ["mrn:iam:group:developers"],
"scopes": ["mrn:iam:scope:full-access"],
"mclearance": "HIGH",
"mannotations": {
"department": "engineering"
}
},
"operation": "api:users:create",
"resource": "mrn:app:users:12345",
"context": {
"timestamp": "2024-01-15T10:30:00Z",
"source_ip": "192.168.1.100"
}
}

Principal

The Principal represents who is making the request. This typically comes from JWT claims or other authentication tokens.

FieldDescription
subSubject identifier (user ID, service account)
mrolesArray of role MRNs assigned to the principal
mgroupsArray of group MRNs the principal belongs to
scopesArray of scope MRNs from the access method
mclearanceSecurity clearance level (LOW, MODERATE, HIGH, MAXIMUM)
mannotationsKey-value metadata about the principal
Audit Consideration

The sub field should always be provided. While omitting it may not affect policy evaluation, principal.sub has first-class representation in the AccessRecord and its absence will impact audit data quality.

Principal in Policies

Access principal fields in Rego via input.principal:

package authz

default allow = false

# Check if principal has admin role
allow {
"mrn:iam:role:admin" in input.principal.mroles
}

# Check security clearance
allow {
input.principal.mclearance == "HIGH"
}

# Check department annotation
allow {
input.principal.mannotations.department == "engineering"
}

Operation

The Operation identifies what action is being performed. Operations follow a consistent naming convention:

<subsystem>:<resource-class>:<verb>

Examples

OperationDescription
iam:identity:createCreate an identity
vault:attributes:readRead vault attributes
api:users:listList users via API
admin:settings:updateUpdate admin settings

See Operations for details on how operations route requests to policies.

Operation in Policies

package authz

default allow = false

# Allow specific operations
allow {
input.operation in {"api:users:read", "api:users:list"}
}

# Pattern matching with glob
allow {
glob.match("*:*:read", [], input.operation)
}

# Parse operation components
allow {
parts := split(input.operation, ":")
parts[0] == "api"
parts[2] == "read"
}

Resource

The Resource identifies the entity being accessed. Resources have metadata—group membership, classification, ownership, and annotations—that policies use to make decisions. The two PORC formats differ in who provides that metadata:

FormatMetadata Provider
MRN StringPolicyEngine resolves via selectors or external resolvers
Fully-Qualified DescriptorPEP provides directly in the request

MRN String

{
"resource": "mrn:app:myservice:document:12345"
}

Fully-Qualified Descriptor

{
"resource": {
"id": "mrn:app:myservice:document:12345",
"owner": "user@example.com",
"group": "mrn:iam:resource-group:documents",
"classification": "MODERATE",
"annotations": {"department": "engineering"}
}
}
Audit Consideration

The resource.id field has first-class representation in the AccessRecord. When using the MRN string format, the PolicyEngine automatically populates resource.id from the provided string. When using the Fully-Qualified Descriptor format, the id field should be provided to ensure complete audit data.

See Resource Resolution for guidance on choosing between these formats, and Resources for details on resource metadata.

Resource in Policies

package authz

default allow = false

# Check if principal owns the resource
allow {
input.principal.sub == input.resource.owner
}

# Check resource classification against clearance
allow {
clearance_levels := {"LOW": 1, "MODERATE": 2, "HIGH": 3, "MAXIMUM": 4}
clearance_levels[input.principal.mclearance] >= clearance_levels[input.resource.classification]
}

# Check resource annotations
allow {
input.resource.annotations.department == input.principal.mannotations.department
}

Context

The Context contains additional information about the request environment. This is free-form and depends on the enforcement point.

Common Context Fields

{
"context": {
"timestamp": "2024-01-15T10:30:00Z",
"source_ip": "10.0.0.1",
"user_agent": "Mozilla/5.0...",
"request_id": "abc-123",
"method": "POST",
"path": "/api/users"
}
}

Context in Policies

package authz

default allow = false

# Allow if all conditions pass
allow {
trusted_network(input.context.source_ip)
not weekend_restricted
}

# Helper: Check trusted network
trusted_network(ip) {
net.cidr_contains("10.0.0.0/8", ip)
}

# Helper: Weekend access restriction
weekend_restricted {
time.weekday(time.now_ns()) == "Saturday"
not "mrn:iam:role:weekend-access" in input.principal.mroles
}

How PORC Connects to Policy Phases

The PORC expression drives the Policy Conjunction evaluation:

PORC Mapping

PORC ComponentUsed By
operationPhase 1 - Routes to operation policy
principal.mrolesPhase 2 - Selects identity policies via roles
principal.mgroupsPhase 2 - Expands to additional roles
resource.groupPhase 3 - Selects resource policy
principal.scopesPhase 4 - Selects scope policies

Complete PORC Example

Here's a fully-populated PORC expression showing all components:

{
"principal": {
"sub": "alice@acme.com",
"mrealm": "acme.com",
"mroles": [
"mrn:iam:role:editor",
"mrn:iam:role:viewer"
],
"mgroups": [
"mrn:iam:group:content-team"
],
"scopes": [
"mrn:iam:scope:full-access"
],
"mclearance": "MODERATE",
"mannotations": {
"department": "marketing",
"employee_id": "12345"
}
},
"operation": "documents:article:update",
"resource": {
"id": "mrn:content:acme.com:article:summer-campaign",
"owner": "bob@acme.com",
"group": "mrn:iam:resource-group:marketing-content",
"classification": "LOW",
"annotations": {
"campaign": "summer-2024",
"status": "draft"
}
},
"context": {
"timestamp": "2024-06-15T14:30:00Z",
"source_ip": "10.0.1.50",
"user_agent": "ContentEditor/2.0",
"request_id": "req-abc-123",
"correlation_id": "corr-xyz-789"
}
}
  • Policy Conjunction: How PORC drives multi-phase evaluation
  • MRN: The identifier format used in PORC
  • Operations: How the operation field routes to policies
  • Roles: Identity policies selected by mroles
  • Groups: Role bundles referenced by mgroups
  • Resources: The resource field and its metadata
  • Resource Groups: Resource policy selection
  • Scopes: Access-method constraints via scopes

Integration

For implementation details on building PORC expressions in your application: