PolicyFlow

Getting Started

Set up your first PolicyFlow project

Welcome to PolicyFlow! This guide will help you set up your first project and write your first authorization policy.

Project Structure

A typical PolicyFlow project has the following structure:

my-project/
├── .env                     # Environment variables (optional)
├── schemas/                 # Schema definitions
│   ├── auth.pfs
│   └── resources.pfs
├── policies/               # Policy files
│   ├── document-access.pf
│   └── admin-access.pf
└── tests/                  # Test files
    ├── document-access.pftest
    └── admin-access.pftest

Your First Schema

Let's start by defining a simple schema for users and documents:

schema BasicSchema {
    // Define a User type
    User type AppUser {
        id: UUID
        email: Email
        name: String
        roles: String[]
        isActive: Boolean = true
    }

    // Define a Resource type
    Resource type Document {
        id: UUID
        title: String
        ownerId: UUID
        classification: String
        createdAt: DateTime
    }

    // Define a Context type
    Context type RequestContext {
        ipAddress: IPAddress
        timestamp: DateTime = DateTime.Now()
    }
}

Your First Policy

Now let's create a simple policy that uses this schema:

import * as Basic from "@/schemas/basic.pfs:BasicSchema";

policy DocumentAccess {
    description: "Controls access to documents based on ownership and classification"
    version: "1.0.0"

    // Specify which types this policy applies to
    schemas {
        User from Basic.AppUser
        Resource from Basic.Document
        Context from Basic.RequestContext
    }

    // Define the authorization rules
    rules {
        // Rule 1: Owners can always access their documents
        rule OwnerAccess {
            when user.id == resource.ownerId
            then ALLOW
            reason: "Document owner has full access"
        }

        // Rule 2: Active users can read public documents
        rule PublicDocumentAccess {
            when user.isActive
                AND resource.classification == "Public"
                AND action == "read"
            then ALLOW
            reason: "Active users can read public documents"
        }

        // Rule 3: Users with admin role can access everything
        rule AdminAccess {
            when "admin" in user.roles
            then ALLOW
            priority: 1000
            reason: "Administrators have full access"
        }
    }
}

Testing Your Policy

Let's write tests to ensure our policy works correctly:

import * as DocPolicy from "@/policies/document-access.pf";

test DocumentAccessTests for DocPolicy {
    // Test Case 1: Owner can access their document
    case "Document owner should have access" {
        given {
            user: {
                id: "user-123",
                email: "owner@example.com",
                name: "Document Owner",
                roles: ["user"],
                isActive: true
            }
            resource: {
                id: "doc-456",
                title: "My Document",
                ownerId: "user-123",
                classification: "Confidential",
                createdAt: DateTime.Parse("2025-06-01T00:00:00Z")
            }
            context: {
                ipAddress: "192.168.1.1"
            }
            action: "read"
        }
        expect: ALLOW
        reason: "Document owner has full access"
    }

    // Test Case 2: Non-owner cannot access confidential document
    case "Non-owner should be denied access to confidential document" {
        given {
            user: {
                id: "user-789",
                email: "other@example.com",
                name: "Other User",
                roles: ["user"],
                isActive: true
            }
            resource: {
                id: "doc-456",
                title: "Confidential Document",
                ownerId: "user-123",
                classification: "Confidential",
                createdAt: DateTime.Parse("2025-06-01T00:00:00Z")
            }
            context: {
                ipAddress: "192.168.1.2"
            }
            action: "read"
        }
        expect: DENY
    }

    // Property-based test
    property "Inactive users should never have access" {
        for User where !(user?.isActive ?? false)
        for Resource
        for Context
        for Action
        expect: DENY
    }
}

Running Your Policies

Once you've written your schemas, policies, and tests, you can:

  1. Validate your policies for syntax errors
  2. Run tests to ensure your logic is correct
  3. Deploy your policies to your authorization service

What's Next?

Now that you've created your first PolicyFlow project, explore these topics: