Skip to content

permitio/billund-demo

Repository files navigation

Billund LEGO Access Control Demo

A Next.js application demonstrating Attribute-Based Access Control (ABAC), Relationship-Based Access Control (ReBAC), and AI-powered chat with Fine-Grained Authorization (FGA) using Permit.io. This demo simulates LEGO's internal product catalog and collaborative document management, where access is controlled through user/resource attributes, hierarchical relationships, and an AI chat agent that respects the same permissions.

Features

AI Chat Agent with Fine-Grained Authorization

The demo includes a LangChain-based AI chat agent that demonstrates how Fine-Grained Authorization (FGA) works with RAG (Retrieval-Augmented Generation):

  • Permission-Aware Retrieval: Uses FAISS vector stores with Permit.io integration to filter documents/products before retrieval
  • Runtime Permission Checks: Uses LangchainPermissionsCheckTool to check access levels (full, masked, metadata-only) for each retrieved item
  • Automatic Data Masking: Applies masking based on permission checks before sending context to the LLM
  • Secure by Default: The LLM only sees information the user is authorized to access, with sensitive data already masked

The chat agent is accessible from both the Products and Documents pages, and respects the same ABAC and ReBAC policies as the rest of the application.

ABAC (Attribute-Based Access Control) - Products

  • Product Catalog - Browse LEGO products with dynamic permissions based on user attributes
  • Masking/Redaction - Confidential information is redacted based on user attributes
  • Grid/List View - Toggle between different product display modes

ReBAC (Relationship-Based Access Control) - Documents

  • Document Library - Collaborative documents with relationship-based permissions
  • Hierarchical Access - Document access derived from product relationships
  • Role Derivation - Product leads automatically get editor access to documents
  • Document Sharing - Product leads can share documents with other users
  • Content Masking - Metadata-only viewers see only document names, content is hidden
  • Accordion View - Expandable document rows showing full content when opened

AI Chat Agent with FGA

  • Intelligent RAG - LangChain-based AI chat agent that answers questions about products and documents
  • Permission-Aware Retrieval - Uses Permit.io to filter and mask information based on user permissions
  • Fine-Grained Data Masking - Automatically redacts sensitive information based on access levels
  • Context-Aware Responses - LLM only sees content the user is authorized to access
  • Multi-Resource Support - Chat about both products and documents with unified access control

Shared Features

  • Demo Personas - Switch between different user roles to see access control in action
  • Policy Engine - Fine-grained access control using Permit.io
  • OIDC Authentication - Secure authentication using NextAuth.js

ABAC Use Case

This demo implements a realistic LEGO product access control scenario:

Access Control Rules

  1. All employees can view released products (public catalog)
  2. Theme designers can view pre-release + public products for their assigned themes
  3. Theme designers can view pre-release + confidential products for their themes, but with masking (redacted pricing/details)
  4. LEGO workstation users get full unmasked access to confidential products for their themes (secure environment)

Product Attributes

  • Theme: City, Space, Castle, Ninjago, Friends, Technic
  • Status: released or pre-release
  • Confidentiality: public or confidential
  • Release Date: ISO date string

User Attributes

  • Organization: Array of theme names the user has access to (e.g., ["City", "Space"])
  • Workstation: office_workstation or lego_workstation (secure facility)
  • Role: employee, designer, manager, team_lead, etc.

Demo Personas

1. General Employee

Attributes: organization: [], workstation: office_workstation, role: employee

Can see (4 products):

  • All released products across all themes
  • NO pre-release products (no theme access)

Example: Regular office employee browsing the public LEGO catalog.


2. City Theme Designer (Office)

Attributes: organization: ["City"], workstation: office_workstation, role: designer

Can see (6 products):

  • All 4 released products
  • City Fire Brigade (pre-release, public, City) - FULL ACCESS
  • City Mega Construction (pre-release, confidential, City) - MASKED ⚠️

Why masked?: Working from office workstation, not secure LEGO facility.


3. Space Theme Designer (LEGO Workstation)

Attributes: organization: ["Space"], workstation: lego_workstation, role: designer

Can see (7 products):

  • All 4 released products
  • Space Colony Base (pre-release, public, Space) - FULL ACCESS
  • Space Intergalactic Cruiser (pre-release, confidential, Space) - FULL UNMASKED ACCESS

Why unmasked?: At secure LEGO workstation, can see all confidential details.


4. Senior Designer (Multi-Theme)

Attributes: organization: ["City", "Space", "Castle"], workstation: office_workstation, role: senior_designer

Can see (10 products):

  • All 4 released products
  • City Fire Brigade (pre-release, public, City) - full
  • Space Colony Base (pre-release, public, Space) - full
  • Dragon Mountain Cave (pre-release, public, Castle) - full
  • City Mega Construction (pre-release, confidential, City) - MASKED ⚠️
  • Space Intergalactic Cruiser (pre-release, confidential, Space) - MASKED ⚠️
  • Castle Kingdom Palace (pre-release, confidential, Castle) - MASKED ⚠️

Why masked?: Has access to 3 themes but working from office, so confidential products are redacted.


5. Ninjago Lead (LEGO Workstation)

Attributes: organization: ["Ninjago"], workstation: lego_workstation, role: team_lead

Can see (5 products):

  • All 4 released products
  • Ninjago Ultimate Showdown (pre-release, confidential, Ninjago) - FULL UNMASKED ACCESS

Why unmasked?: Team lead at LEGO workstation gets full access to confidential Ninjago products.


6. Friends Theme Manager (Office)

Attributes: organization: ["Friends"], workstation: office_workstation, role: manager

Can see (5 products):

  • All 4 released products
  • Friends Heartlake Resort (pre-release, confidential, Friends) - MASKED ⚠️

Why masked?: Working from office, so sensitive pricing and details are redacted.


ReBAC Use Case

This demo implements Relationship-Based Access Control (ReBAC) for collaborative document management. Documents belong to products, and access is derived through hierarchical relationships.

Access Control Rules

  1. Product leads automatically get editor access to all documents belonging to their products
  2. Product stakeholders automatically get viewer access (metadata only - name visible, content masked) to documents belonging to their products
  3. Direct role assignments - Product leads can share documents by granting editor role directly to users
  4. Document permissions:
    • Editor: Can view full content, edit, and share documents
    • Viewer: Can only see document name (content is masked)
    • Moderator: Can view, edit, and share documents (same as editor currently)

Document Structure

  • Document Types: design, financial, marketing, spec
  • Parent-Child Relationship: Each document belongs to a product via parent relationship
  • Role Derivation:
    • product:leaddocument:editor (via parent relation)
    • product:stakeholderdocument:viewer (via parent relation)

Document Access Examples

Product Lead (e.g., City Designer as lead of City Police Station):

  • Can view the product
  • Automatically gets editor role on all documents belonging to the product
  • Can view full document content
  • Can edit documents
  • Can share documents with other users (granting them editor role)

Product Stakeholder (e.g., Senior Designer as stakeholder):

  • Cannot view the product directly
  • Automatically gets viewer role on all documents belonging to the product
  • Can only see document names (content is masked/hidden)
  • Cannot edit or share

Direct Editor (user granted editor role via sharing):

  • Can view full document content
  • Can edit the document
  • Cannot share (only product leads can share)

Prerequisites

  • Node.js 18+ installed
  • Docker (for running Permit.io PDP locally)
  • Permit.io account (free at permit.io)

Getting Started

1. Install Dependencies

npm install

2. Set up Permit.io

  1. Create a free account at permit.io
  2. Create a new project
  3. Copy your API key

3. Configure Environment Variables

Copy .env.example to .env.local:

cp .env.example .env.local

Edit .env.local with your configuration:

# NextAuth
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=your-secret-key-here

# OIDC Provider
OIDC_CLIENT_ID=your-client-id
OIDC_CLIENT_SECRET=your-client-secret
OIDC_ISSUER=https://your-oidc-provider.com

# Permit.io
PERMIT_API_KEY=your-permit-api-key
PERMIT_PDP_URL=http://localhost:7766

Generate NEXTAUTH_SECRET:

openssl rand -base64 32

4. Run Permit.io PDP (Policy Decision Point)

Start the local PDP container:

docker run -p 7766:7000 --env PDP_API_KEY=<YOUR_PERMIT_API_KEY> permitio/pdp-v2:latest

5. Set up Permit.io Configuration

Run the setup script to configure ABAC policies, condition sets, and demo users:

npm run setup:permit

This script creates:

  • Product resource type with attributes (theme, confidentiality, status, releaseDate)
  • User attributes (organization, workstation, role)
  • 6 condition sets (3 resource sets + 3 user sets)
  • 4 condition set rules implementing the ABAC policies
  • 2 roles (employee, designer)
  • 6 demo personas synced with attributes
  • 15 product instances synced with attributes

6. Set up Python Chat Agent Service

The AI chat agent requires a Python service. You can run it via Docker Compose (recommended for development):

# Start all services (PDP, Next.js app, Python chat agent)
docker-compose -f docker-compose.dev.yml up --build

Or run the Python service separately:

  1. Install Python dependencies:
cd services/chat-agent
pip install -r requirements.txt
  1. Export data from TypeScript to JSON:
npm run export:data
  1. Set environment variables in services/chat-agent/.env:
PERMIT_API_KEY=your_permit_api_key
PERMIT_PDP_URL=http://localhost:7766
OPENAI_API_KEY=sk-...
  1. Run the FastAPI server:
cd services/chat-agent
uvicorn api_server:app --reload --port 8000

7. Run the Development Server

npm run dev

Open http://localhost:3000 in your browser.

Project Structure

.
├── app/
│   ├── api/
│   │   ├── auth/[...nextauth]/     # NextAuth API routes
│   │   ├── products/               # Product catalog API with ABAC
│   │   ├── documents/               # Document library API with ReBAC
│   │   ├── chat/                    # Chat agent API proxy
│   │   ├── users/                   # User listing for document sharing
│   │   └── demo/                    # Demo persona switching
│   ├── products/                    # Product catalog page (ABAC demo)
│   ├── documents/                   # Document library page (ReBAC demo)
│   ├── chat/                        # Dedicated chat page
│   ├── dashboard/                   # Protected dashboard
│   └── page.tsx                     # Home page
├── components/
│   ├── products/                    # Product card components
│   ├── documents/                   # Document components (PermissionDialog, ShareDialog)
│   ├── chat/                        # Chat dialog component
│   └── demo/                        # Persona switcher
├── services/
│   └── chat-agent/                  # Python LangChain chat agent service
│       ├── api_server.py            # FastAPI server
│       ├── chat_service.py          # Chat agent logic
│       ├── permit_masked_retriever.py # Permission-aware retriever wrapper
│       ├── data_loader.py           # Data loading utilities
│       └── data/                    # JSON data files (products, documents)
├── lib/
│   ├── data/
│   │   ├── products.ts              # Product data (15 products)
│   │   ├── documents.ts             # Document data (14 documents)
│   │   └── personas.ts              # Demo personas (6 users)
│   ├── permit.ts                    # Permit.io SDK setup
│   └── permit-helpers.ts            # ABAC and ReBAC helper functions
├── scripts/
│   ├── setup-permit.ts              # Permit.io configuration script
│   └── export-data.ts               # Export TS data to JSON for Python service
├── docker-compose.dev.yml           # Docker Compose for dev environment
└── .env.local                       # Environment variables

How ABAC Works in This Demo

1. User Attributes are Synced to Permit.io

When a user logs in or switches persona, their attributes are synced:

await permit.api.syncUser({
  key: "persona-city-office",
  email: "[email protected]",
  attributes: {
    organization: ["City"],
    workstation: "office_workstation",
    role: "designer"
  }
});

2. Product Instances are Synced to Permit.io

Products are synced with their attributes:

await permit.api.resourceInstances.create({
  resource: "product",
  key: "prod-008",
  attributes: {
    theme: "City",
    status: "pre-release",
    confidentiality: "confidential",
    releaseDate: "2025-09-01"
  }
});

3. Condition Sets Define Rules

Resource Sets match products by attributes:

{
  key: "released_products",
  type: "resourceset",
  resource_id: "product",
  conditions: {
    allOf: [{ "resource.status": { equals: "released" } }]
  }
}

User Sets match users by attributes:

{
  key: "theme_access_users",
  type: "userset",
  conditions: {
    allOf: [
      {
        "user.organization": {
          "array_contains": { ref: "resource.theme" }
        }
      }
    ]
  }
}

4. Condition Set Rules Connect User Sets to Resource Sets

{
  user_set: "theme_access_users",
  resource_set: "prerelease_confidential",
  permission: "product:view"
}

This rule means: "Users whose organization contains the product's theme can view pre-release confidential products (but masked)"

5. PDP Evaluates Permissions

The app queries the PDP to check all permissions in a single batch call:

const response = await fetch(`${pdpUrl}/user-permissions`, {
  method: "POST",
  body: JSON.stringify({
    user: {
      key: userId,
      attributes: { organization, workstation }
    },
    resources: ["prod-001", "prod-002", ...],
    context: { enable_abac_user_permissions: true }
  })
});

6. UI Applies Masking

Based on permissions returned, the UI either shows full details or applies masking:

if (canViewFull) {
  accessLevel = "full";
} else if (canView && product.confidentiality === "confidential") {
  accessLevel = "masked";
  displayProduct = applyProductMask(product); // Redact sensitive fields
}

Key Concepts

ABAC: Masking/Redaction

When a user has view permission but not view_full permission on a confidential product:

  • Price is hidden (shows [REDACTED])
  • Description is redacted
  • Image is replaced with placeholder
  • Product name is still visible

ReBAC: Role Derivation

Documents inherit access from their parent products through relationship tuples:

  1. Relationship Tuples: product:prod-001 parent document:doc-001

    • Defines that doc-001 belongs to prod-001 via the parent relation
  2. Role Derivation Rules:

    • Users with product:lead role on a product automatically get document:editor role on all child documents
    • Users with product:stakeholder role on a product automatically get document:viewer role on all child documents
  3. Direct Assignments: Product leads can share documents by directly assigning document:editor role to users

ReBAC: Content Masking

When a user has only view_metadata permission on a document:

  • Document name is visible
  • Document content is completely hidden (shows placeholder text)
  • Product name is visible
  • Document type badge is visible

LEGO Workstation

A secure environment attribute that grants full access to confidential information. This simulates:

  • Physical security (only accessible in LEGO facilities)
  • Network security (isolated workstations)
  • Compliance requirements (audit trails for sensitive data access)

Theme Organization

Represents which product lines a user works on. Uses array_contains matching to check if the user's organization array includes the product's theme.

Development

Available Scripts

  • npm run dev - Start development server
  • npm run build - Build for production
  • npm start - Start production server
  • npm run setup:permit - Configure Permit.io policies
  • npm run export:data - Export TypeScript data to JSON for Python chat agent

Testing Different Personas

Use the persona switcher in the sidebar to test different access levels without logging out. Each persona demonstrates different ABAC and ReBAC scenarios:

  • Products Page: Test ABAC with attribute-based filtering and masking
  • Documents Page: Test ReBAC with relationship-based access and role derivation
  • Chat Agent: Ask questions about products and documents - the AI respects the same permissions as the UI

Switch between personas to see how both access control models work together, and how the AI chat agent respects the same permissions.

Using the AI Chat Agent

The chat agent is available from both the Products and Documents pages, or visit /chat directly. Try asking:

  • "Tell me about City products"
  • "What documents are available for Space products?"
  • "Which confidential products can I access?"
  • "Show me products I can see with full details"

The chat agent will:

  1. Retrieve relevant products/documents using semantic search
  2. Filter out items you don't have access to (using Permit.io)
  3. Check access levels for each retrieved item
  4. Apply masking to sensitive information
  5. Generate a response based only on what you're authorized to see

Potential Improvements

While the current setup process works well, here are some enhancements that could make it even easier for new users:

Setup Automation

  • Environment variable validation: Check for required env vars on app startup and provide helpful error messages
  • Setup verification script: Add npm run verify:setup to check if Permit.io is properly configured
  • Docker Compose integration: Auto-start PDP alongside the Next.js dev server
  • Health check endpoint: API route to verify PDP connectivity and configuration status

Developer Experience

  • Pre-commit hooks: Validate that setup has been run before allowing commits
  • Setup status indicator: Show in UI if demo is properly configured
  • Interactive setup wizard: Guide users through account creation and configuration
  • Error recovery: Better error messages with actionable next steps when PDP is unreachable

These improvements would reduce the manual setup steps while maintaining the educational value of understanding each component.

AI Chat Agent Architecture

The chat agent demonstrates how to integrate Fine-Grained Authorization with RAG (Retrieval-Augmented Generation):

  1. Vector Store Setup: Products and documents are embedded using OpenAI embeddings and stored in FAISS vector stores
  2. Permission-Aware Retrieval: Before retrieval, the system uses Permit.io to filter out items the user doesn't have access to
  3. Runtime Permission Checks: For each retrieved item, LangchainPermissionsCheckTool checks access levels:
    • Products: view_full (unmasked) vs view (may be masked if confidential)
    • Documents: view (full) vs view_metadata (content masked)
  4. Data Masking: Based on permission checks, sensitive information is redacted before sending to the LLM
  5. Context Generation: The LLM receives only the information the user is authorized to see, with masking already applied
  6. Response Generation: The LLM generates responses based on the masked, permission-filtered context

This ensures that the AI never exposes information the user shouldn't have access to, and the responses reflect only what the user can see.

Learn More

License

MIT

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published