Real-world scenarios demonstrating fine-grained authorization for AI agents.
A customer support AI agent needs to help resolve tickets but should only access customer data relevant to the ticket, not browse all customer records.
Agent: support-bot
User Context: support-agent-jane
Tool: customer-database
Operations:
- read_ticket ✅ (allowed)
- read_customer_by_ticket ✅ (allowed - scoped to ticket)
- search_all_customers ❌ (denied - too broad)
- export_customer_data ❌ (denied - requires manager)
- delete_customer ❌ (denied - requires admin)
- Prompt Injection Defense: Attacker can't trick agent into "show me all customers with credit cards"
- Compliance: GDPR/CCPA - agent only accesses data with legitimate purpose
- Audit Trail: Every customer record access is logged with ticket context
{
"tool": "customer-db",
"operation": "read_customer",
"params": {"ticket_id": "TKT-1234"},
"context": {"user": "jane", "role": "support-agent", "department": "support"}
}
// ✅ ALLOWED - scoped to ticket
{
"tool": "customer-db",
"operation": "search_customers",
"params": {"query": "SELECT * FROM customers"},
"context": {"user": "jane", "role": "support-agent", "department": "support"}
}
// ❌ DENIED - bulk access not permitted for support agentsAn AI code review agent should only access repositories the developer owns or is assigned to review, not all company code.
Agent: code-reviewer
User Context: developer-alice
Tool: github
Operations:
- read_pr ✅ (if assigned as reviewer)
- comment_pr ✅ (if assigned as reviewer)
- read_repo ✅ (if team member)
- approve_pr ✅ (if senior+ and assigned)
- merge_pr ❌ (requires human approval)
- read_other_team_repo ❌ (denied - not team member)
- IP Protection: Agent can't exfiltrate code from other teams
- Separation of Duties: Agent reviews but human merges
- Least Privilege: Only repos relevant to current work
{
"tool": "github",
"operation": "read_file",
"params": {"repo": "acme/auth-service", "path": "src/auth.go"},
"context": {"user": "alice", "team": "engineering", "project": "auth-service"}
}
// ✅ ALLOWED - alice is on engineering team
{
"tool": "github",
"operation": "read_file",
"params": {"repo": "acme/payroll-service", "path": "src/salaries.go"},
"context": {"user": "alice", "team": "engineering", "project": "auth-service"}
}
// ❌ DENIED - payroll-service is HR team onlyA BI agent can query sales data but should not see individual customer names or payment details - only aggregates.
Agent: analytics-bot
User Context: analyst-bob
Tool: data-warehouse
Operations:
- query_aggregates ✅ (SUM, COUNT, AVG)
- query_anonymized ✅ (hashed customer IDs)
- query_pii_columns ❌ (name, email, SSN)
- query_payment_data ❌ (requires finance role)
- export_raw_data ❌ (requires data-admin)
- Data Minimization: Agent only sees what's needed for analysis
- PII Protection: Can't accidentally include names in reports
- Regulatory Compliance: SOX, PCI-DSS for financial data
{
"tool": "warehouse",
"operation": "query",
"params": {"sql": "SELECT region, SUM(revenue) FROM sales GROUP BY region"},
"context": {"user": "bob", "role": "analyst", "department": "analytics"}
}
// ✅ ALLOWED - aggregate query
{
"tool": "warehouse",
"operation": "query",
"params": {"sql": "SELECT customer_name, email, purchase_amount FROM sales"},
"context": {"user": "bob", "role": "analyst", "department": "analytics"}
}
// ❌ DENIED - query includes PII columns (customer_name, email)A deployment agent can deploy to staging but requires additional approval for production. It should never access the production database directly.
Agent: deploy-bot
User Context: devops-frank
Tool: kubernetes, database
Operations:
- deploy_staging ✅ (allowed)
- deploy_production ⚠️ (requires approval workflow)
- rollback_staging ✅ (allowed)
- rollback_production ✅ (allowed - safety operation)
- query_staging_db ✅ (allowed)
- query_production_db ❌ (denied - use read replica)
- drop_table ❌ (denied - always)
- Blast Radius: Staging mistakes don't affect production
- Change Management: Production deploys need human approval
- Data Protection: No direct production DB access
{
"tool": "kubernetes",
"operation": "deploy",
"params": {"env": "staging", "image": "app:v2.1.0"},
"context": {"user": "frank", "team": "devops", "project": "infrastructure"}
}
// ✅ ALLOWED - staging deployment
{
"tool": "kubernetes",
"operation": "deploy",
"params": {"env": "production", "image": "app:v2.1.0"},
"context": {"user": "frank", "team": "devops", "project": "infrastructure"}
}
// ⚠️ PENDING APPROVAL - production requires sign-off
{
"tool": "postgres",
"operation": "query",
"params": {"database": "production", "sql": "SELECT * FROM users"},
"context": {"user": "frank", "team": "devops", "project": "infrastructure"}
}
// ❌ DENIED - use read replica for production queriesAn HR assistant agent can help with general HR queries but salary and performance data requires manager-level access.
Agent: hr-assistant
User Context: hr-coordinator-eve
Tool: hr-system
Operations:
- read_employee_directory ✅ (public info)
- read_org_chart ✅ (public info)
- read_pto_balance ✅ (for requesting employee)
- read_salary ❌ (requires hr-manager)
- read_performance_review ❌ (requires manager of employee)
- modify_salary ❌ (requires hr-director + finance)
- terminate_employee ❌ (requires hr-director + legal)
- Confidentiality: Salary data is highly sensitive
- Need-to-Know: Performance reviews only for direct managers
- Dual Control: Critical actions need multiple approvers
{
"tool": "hr-system",
"operation": "read_employee",
"params": {"employee_id": "E123", "fields": ["name", "department", "title"]},
"context": {"user": "eve", "role": "hr-coordinator"}
}
// ✅ ALLOWED - basic employee info
{
"tool": "hr-system",
"operation": "read_employee",
"params": {"employee_id": "E123", "fields": ["salary", "bonus"]},
"context": {"user": "eve", "role": "hr-coordinator"}
}
// ❌ DENIED - salary requires hr-manager roleA finance agent can process invoices but has transaction limits and requires approval for large amounts.
Agent: finance-bot
User Context: accountant-grace
Tool: payment-system
Operations:
- create_invoice ✅ (any amount)
- approve_invoice_small ✅ (< $10,000)
- approve_invoice_medium ⚠️ ($10k-$100k, requires manager)
- approve_invoice_large ⚠️ (> $100k, requires CFO)
- process_payment ✅ (if invoice approved)
- modify_bank_details ❌ (requires treasury + dual approval)
- void_payment ⚠️ (requires manager + audit log)
- Fraud Prevention: Large transactions need human oversight
- Segregation of Duties: Different people create vs approve
- Audit Requirements: SOX compliance for financial controls
{
"tool": "payments",
"operation": "approve_invoice",
"params": {"invoice_id": "INV-5678", "amount": 5000},
"context": {"user": "grace", "role": "accountant", "department": "finance"}
}
// ✅ ALLOWED - under $10k limit
{
"tool": "payments",
"operation": "approve_invoice",
"params": {"invoice_id": "INV-9012", "amount": 75000},
"context": {"user": "grace", "role": "accountant", "department": "finance"}
}
// ⚠️ ESCALATED - requires finance-manager approvalA legal research agent can access contracts and legal documents but attorney-client privileged communications require attorney supervision.
Agent: legal-research
User Context: paralegal-pat
Tool: document-management
Operations:
- search_contracts ✅ (allowed)
- read_contract ✅ (if assigned to matter)
- search_privileged ❌ (requires attorney)
- read_privileged ❌ (requires attorney)
- share_externally ⚠️ (requires attorney review)
- delete_document ❌ (requires legal-hold check)
- Privilege Protection: Accidental disclosure waives privilege
- Matter Boundaries: Only access documents for assigned cases
- Legal Hold: Can't delete documents under litigation hold
{
"tool": "legal-dms",
"operation": "search",
"params": {"query": "vendor agreement", "matter": "M-2024-001"},
"context": {"user": "pat", "role": "paralegal", "matter": "M-2024-001"}
}
// ✅ ALLOWED - searching within assigned matter
{
"tool": "legal-dms",
"operation": "search",
"params": {"query": "attorney notes", "include_privileged": true},
"context": {"user": "pat", "role": "paralegal", "matter": "M-2024-001"}
}
// ❌ DENIED - privileged documents require attorneyA medical assistant agent can access patient records but only for patients with active appointments, and only the minimum necessary information.
Agent: medical-assistant
User Context: nurse-nancy
Tool: ehr-system
Operations:
- read_patient_summary ✅ (if active appointment)
- read_vitals ✅ (if active appointment)
- read_full_history ⚠️ (requires physician order)
- read_psychiatric_notes ❌ (requires psychiatry dept)
- read_substance_abuse ❌ (requires 42 CFR Part 2 consent)
- export_patient_data ❌ (requires privacy officer)
- HIPAA Minimum Necessary: Only access needed for treatment
- Special Categories: Mental health, substance abuse have extra protection
- Break-the-Glass: Emergency access with audit trail
{
"tool": "ehr",
"operation": "read_patient",
"params": {"patient_id": "P12345", "sections": ["demographics", "vitals"]},
"context": {"user": "nancy", "role": "nurse", "appointment": "APT-789"}
}
// ✅ ALLOWED - patient has active appointment with this nurse
{
"tool": "ehr",
"operation": "read_patient",
"params": {"patient_id": "P12345", "sections": ["psychiatric_notes"]},
"context": {"user": "nancy", "role": "nurse", "appointment": "APT-789"}
}
// ❌ DENIED - psychiatric notes require psychiatry department accessAll these use cases follow the same authorization pattern:
// Gateway intercepts every tool call
func (g *Gateway) HandleToolCall(req ToolCallRequest) (*ToolCallResponse, error) {
// 1. Build authorization context
authzReq := authz.Request{
User: req.Context.User,
Role: req.Context.Role,
Team: req.Context.Team,
Project: req.Context.Project,
Tool: req.Tool,
Operation: req.Operation,
Resource: extractResource(req.Params),
}
// 2. Check with OpenFGA
result, err := g.fga.Check(ctx, authzReq)
if err != nil {
return nil, err
}
// 3. Log the decision
g.audit.Log(authzReq, result)
// 4. Allow or deny
if !result.Allowed {
return &ToolCallResponse{
Allowed: false,
Reason: result.Reason,
}, nil
}
// 5. Forward to actual tool
return g.proxy.Forward(req)
}To add these use cases to the demo UI, update the scenarios in gateway/internal/handler/handler.go:
// Add to HandleDemoScenarios
{
ID: "pii-protection",
Name: "PII Protection: Support Agent",
Description: "Support agent queries customer by ticket - ALLOWED",
Request: ToolCallRequest{
Tool: "customer-db",
Operation: "read_customer_by_ticket",
Params: map[string]interface{}{"ticket_id": "TKT-1234"},
Context: ToolCallContext{User: "jane", Project: "support", Team: "support"},
},
Expected: "allowed",
},
{
ID: "pii-blocked",
Name: "PII Protection: Bulk Query Blocked",
Description: "Support agent tries bulk customer query - DENIED",
Request: ToolCallRequest{
Tool: "customer-db",
Operation: "search_all_customers",
Params: map[string]interface{}{},
Context: ToolCallContext{User: "jane", Project: "support", Team: "support"},
},
Expected: "denied",
},| Use Case | Key Protection | Compliance |
|---|---|---|
| Customer Support | PII scoping | GDPR, CCPA |
| Code Review | Repository boundaries | IP Protection |
| Data Analysis | Column-level security | SOX, PCI-DSS |
| DevOps | Environment isolation | Change Management |
| HR | Salary compartmentalization | Privacy |
| Finance | Transaction limits | SOX, Fraud Prevention |
| Legal | Privilege protection | Attorney-Client |
| Healthcare | Minimum necessary | HIPAA |
Each use case demonstrates that authorization is not just about roles - it's about:
- Context (which project, which ticket, which patient)
- Operations (read vs write vs delete)
- Data sensitivity (PII, financial, privileged)
- Approval workflows (escalation for high-risk actions)
This is what OpenFGA and ReBAC enable that traditional RBAC cannot.