DAY 10 WEEK 2: CORE SERVICES

Membership Service Deep Dive

Master graph-based role management with Neo4j β€” identities, role hierarchies, delegations, access reviews, semantic search, and multi-tenant assignments.

Identity is more than just "who you are." It's a web of relationshipsβ€”who you work with, what teams you belong to, what roles you hold, and where those roles apply. Traditional relational databases struggle with these interconnected relationships. That's why the Membership Service uses Neo4j, a graph database where relationships are first-class citizens. Today you'll learn to think in graphs.

πŸ“‹Learning Objectives

  • Understand Neo4j graph database concepts and why it's ideal for identity relationships
  • Learn about Identity, Role, Group, and Resource entities
  • Explore relationship hierarchies and inheritance patterns
  • Create and query role assignments with location scoping
  • Understand delegations and access reviews
  • Use semantic/vector search for identity discovery
  • Learn how Membership integrates with PDP as a Policy Information Point (PIP)

🎯Membership Service Overview

Think of your organization as a living organism. People join teams, get promoted, move departments, take on temporary responsibilities, and eventually leave. The Membership Service tracks all of thisβ€”not just static "Alice has role X" but dynamic, time-bounded, location-scoped relationships that change constantly.

The Membership Service is the identity fabric of EmpowerNow β€” managing the complex web of relationships between users, roles, groups, resources, and organizational locations.

Core Capabilities

  • Identity Management: Users, accounts, groups, and their attributes
  • Role Management: Hierarchical roles with inheritance
  • Location-Scoped Assignments: Role assignments bounded to organizational units
  • Delegations: Time-bounded privilege delegation between users
  • Access Reviews: Periodic certification of access rights
  • Semantic Search: Vector-based identity and role discovery
  • Policy Information Point: Provides user context to PDP for authorization decisions
πŸ”— Service Endpoint

https://membership.self.empowernow.ai (Port 8003)
API Docs: /docs

πŸ›οΈEntity Model

In a graph database, nodes are things (users, roles, groups) and edges are relationships between them (HAS_ROLE, MEMBER_OF). Unlike SQL tables where relationships are implicit via foreign keys, in Neo4j relationships are explicit, queryable, and can have their own properties like "assigned_at" or "expires_on."

The membership service manages these core entities:

Membership Entity Model
flowchart TB User["πŸ‘€ User
━━━━━━
id, email, name"] Role["🎭 Role
━━━━━━
id, name, type"] Group["πŸ‘₯ Group
━━━━━━
id, name"] Location["🏒 Location
━━━━━━
id, name, path"] User -->|"HAS_ROLE"| Role User -->|"MEMBER_OF"| Group Role -->|"INHERITS"| Role Group -->|"BELONGS_TO"| Location style User fill:#0891b2,color:#fff style Role fill:#7c3aed,color:#fff style Group fill:#059669,color:#fff style Location fill:#f59e0b,color:#000

Entity Types

  • User: Individual identity (from IdP)
  • Role: Permission container (Admin, Editor, Viewer)
  • Group: Collection of users and/or other groups
  • Location: Organizational unit (Department, Team, Project)

πŸ”—Relationship Types

Relationships are the superpower of graph databases. "Alice is an Admin" is simple. But "Alice is an Admin in Engineering, a Viewer in Marketing, and has delegated approval rights from Bob until February"β€”that's where Neo4j shines.
  • HAS_ROLE: User has a role (direct assignment)
  • MEMBER_OF: User or Group belongs to a Group
  • INHERITS: Role inherits from parent role
  • BELONGS_TO: Entity belongs to a location
  • SCOPED_AT: Role assignment scoped to location

Location-Scoped Roles

A user can have different roles at different locations:

# Alice is Admin at Engineering, but Viewer at Marketing
(alice:User)-[:HAS_ROLE {location: "engineering"}]->(admin:Role)
(alice:User)-[:HAS_ROLE {location: "marketing"}]->(viewer:Role)

πŸ”¬Exercise 1: Access Neo4j Browser

Neo4j comes with a beautiful browser interface for exploring your graph. Unlike SQL where you write SELECT statements, Neo4j uses Cypherβ€”a pattern-matching query language that reads like ASCII art. (user)-[:HAS_ROLE]->(role) literally looks like a relationship!
  1. Open http://localhost:7474
  2. Connect with default credentials (neo4j/neo4j or as configured)
  3. Explore the database schema

View Schema

// Show all node labels
CALL db.labels()

// Show all relationship types
CALL db.relationshipTypes()

// Visualize schema
CALL db.schema.visualization()

πŸ”Exercise 2: Query Users and Roles

Cypher queries are remarkably intuitive. You describe the pattern you're looking for, and Neo4j finds all matches. Want users with admin roles? Draw the pattern: (u:User)-[:HAS_ROLE]->(r:Role {name: 'admin'}). The database does the rest.
// Find all users
MATCH (u:User) RETURN u.id, u.email, u.name LIMIT 10

// Find user's direct roles
MATCH (u:User {id: 'user-123'})-[:HAS_ROLE]->(r:Role)
RETURN r.name, r.description

// Find all roles (including inherited)
MATCH (u:User {id: 'user-123'})-[:HAS_ROLE|MEMBER_OF*]->(r:Role)
RETURN DISTINCT r.name

// Find users with specific role
MATCH (u:User)-[:HAS_ROLE]->(r:Role {name: 'admin'})
RETURN u.email, u.name

βž•Exercise 3: Create Role Assignment via API

While you can query Neo4j directly, in production you'll use the Membership API. This ensures proper validation, auditing, and cache invalidation. Every role assignment is a business event that gets tracked and can be reviewed.
# Assign role to user
curl -k -X POST https://membership.self.empowernow.ai/api/v1/assignments \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -d '{
    "user_id": "user-123",
    "role_id": "editor",
    "location_id": "engineering",
    "expires_at": "2025-12-31T23:59:59Z"
  }'

Query User Roles via API

# Get user's effective roles
curl -k https://membership.self.empowernow.ai/api/v1/roles/user-123 \
  -H "Authorization: Bearer $ACCESS_TOKEN"

πŸ”„How PDP Uses Membership (PIP Integration)

Here's where everything connects. When PDP asks "Can Alice delete this document?", it doesn't have Alice's roles. It queries the Membership service through a Policy Information Point (PIP). This returns Alice's effective roles, group memberships, and active delegationsβ€”everything needed for the policy decision.

When PDP evaluates a policy, it queries Membership for user context via the Policy Information Point (PIP) endpoint:

  1. PDP receives authorization request with user ID
  2. MembershipPIP queries Membership service at /api/v1/pip/membership/subject-enrichment
  3. Membership returns effective roles, groups, delegations, and attributes
  4. PDP evaluates policy with enriched subject context

PIP Endpoint Example

# Get enriched subject for PDP policy evaluation
curl -k "https://membership.self.empowernow.ai/api/v1/pip/membership/subject-enrichment?subject_id=user-123" \
  -H "Authorization: Bearer $ACCESS_TOKEN"
πŸ’‘ Performance Note

Membership results are cached in Redis. The cache TTL is configurable. Direct queries to Neo4j only happen on cache miss. Circuit breakers protect against cascading failures.

πŸ§ͺ Try It: Query User Roles via API Interactive

Copy curl and run in your terminal to fetch a user's effective roles from the Membership service.

βœ… What to Expect

You should see an array of roles assigned to the user, including direct assignments and inherited roles through group membership.

πŸ”Œ Try It: PIP Subject Enrichment Interactive

Copy curl and run in your terminal. This is what PDP calls to get enriched subject context for authorization decisions.

βœ… What to Expect

The response includes: effective roles, group memberships, active delegations, and subject attributesβ€”everything PDP needs for policy evaluation.

πŸš€The Identity Graph Journey

Let's trace how a role lookup works from request to response. Understanding this flow helps you debug access issues and optimize performance in production environments.
Role Resolution Flow
sequenceDiagram participant App as 🌐 Application participant API as πŸ“‘ Membership API participant Cache as ⚑ Redis Cache participant Neo as πŸ”΅ Neo4j App->>API: GET /users/alice/roles API->>Cache: Check role cache alt Cache Hit Cache-->>API: Cached roles else Cache Miss API->>Neo: MATCH (u:User {id:'alice'})-[:HAS_ROLE|MEMBER_OF*]->(r:Role) Neo-->>API: Role nodes + relationships API->>Cache: Store with TTL end API->>API: Merge direct + inherited roles API->>API: Filter by active delegations API->>API: Apply location scoping API-->>App: Effective roles response

Role Resolution Steps

  1. Cache Check: Redis is checked first for the user's cached roles
  2. Graph Traversal: On cache miss, Cypher query traverses HAS_ROLE and MEMBER_OF edges
  3. Inheritance Resolution: Roles inherited through role hierarchy are collected
  4. Delegation Merge: Active delegations are added to effective permissions
  5. Location Scoping: Roles are filtered by the requested location context
  6. Response + Cache: Results are cached and returned
Graph Traversal Example
flowchart LR subgraph Users["Users"] Alice["πŸ‘€ Alice"] Bob["πŸ‘€ Bob"] end subgraph Groups["Groups"] Eng["πŸ‘₯ Engineering"] DevOps["πŸ‘₯ DevOps"] end subgraph Roles["Roles"] Admin["🎭 Admin"] Editor["🎭 Editor"] Viewer["🎭 Viewer"] end subgraph Locations["Locations"] Prod["🏒 Production"] Dev["🏒 Development"] end Alice -->|"MEMBER_OF"| Eng Alice -->|"HAS_ROLE
@Prod"| Editor Eng -->|"HAS_ROLE"| Viewer Bob -->|"HAS_ROLE
@Prod"| Admin Bob -.->|"DELEGATES TO
until Feb 1"| Alice DevOps -->|"BELONGS_TO"| Prod Admin -->|"INHERITS"| Editor Editor -->|"INHERITS"| Viewer style Alice fill:#0891b2,color:#fff style Admin fill:#7c3aed,color:#fff style Editor fill:#7c3aed,color:#fff style Viewer fill:#7c3aed,color:#fff style Prod fill:#f59e0b,color:#000
πŸ“Š Reading the Graph

In this example, Alice has:

  • Direct: Editor role at Production
  • Via Group: Viewer role (Engineering group has Viewer)
  • Via Inheritance: Editor inherits Viewer permissions
  • Via Delegation: Bob's Admin permissions until Feb 1

🀝Delegations

Real organizations aren't static. Managers go on vacation. Projects need temporary approval chains. Someone covers for a colleague. Delegations model these temporary permission transfersβ€”with automatic expiration, audit trails, and the ability to revoke at any time.

Delegations allow users to temporarily grant their permissions to others β€” essential for vacation coverage, temporary assignments, and approval workflows.

Create a Delegation via API

# Create delegation
curl -k -X POST https://membership.self.empowernow.ai/api/v1/delegations \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -d '{
    "delegator_id": "alice-uuid",
    "delegate_id": "bob-uuid",
    "permission": "approve_expense",
    "starts_at": "2026-01-15T00:00:00Z",
    "expires_at": "2026-02-01T00:00:00Z",
    "reason": "Vacation coverage"
  }'
⚠️ Delegation Governance

Delegations are audited and can be revoked at any time. Expired delegations are automatically excluded from PIP responses.

πŸ€–AI Agent Authorization

In the age of AI, agents operate "on behalf of" usersβ€”touching sensitive data, invoking tools, and spending budgets. The Membership service tracks user-bound agent delegations with explicit capabilities, budget limits, and step controls. This is the foundation of ARIA (Agent Relationship-based Identity & Authorization).

Why AI Agent Authorization Matters

  • Identity Binding: Ensure an agent is truly acting for a specific user/service pair
  • Delegation Clarity: Explicitly constrain what an agent can do (capabilities) and for how long
  • Data Scope: Enforce tenant/row/column restrictions for safe RAG (Retrieval-Augmented Generation)
  • Cost Control: Attach budget_usd and max_steps to bound spend and chain length
  • Identity Chaining: Express eligibility for downstream provider tokens

The DELEGATES_TO Relationship

When a user delegates to an AI agent, the relationship carries rich metadata:

// User-to-Agent delegation in Neo4j
(user:User)-[:DELEGATES_TO {
    id: "delegation:user1-to-agent1",
    status: "active",              // active|paused|revoked|expired
    capabilities: ["mcp:flights:search", "mcp:flights:book"],
    budget_usd: 25.0,              // Max spend for this delegation
    max_steps: 5,                  // Max tool invocations
    valid_from: datetime(),
    expires_at: datetime("2026-02-01"),
    jkt: "sha256:abc123..."        // DPoP key thumbprint
}]->(agent:AIAgent)

PIP Endpoints for AI Authorization

EndpointPurposeReturns
/pip/membership/capabilities What can this agent do for this user? ["mcp:flights:search", "mcp:flights:book"]
/pip/membership/delegations Active delegations with budget/steps {budget_usd: 25.0, max_steps: 5, ...}
/pip/membership/data-scope What data can this subject access? {tenant_ids: [...], row_filter_sql: "..."}
/pip/membership/step-up Does this action require MFA? {mfa_required: true, level: "strong"}
/pip/membership/chain-eligibility What downstream tokens can be obtained? [{audience: "api.flights.com", scopes: [...]}]
πŸ”— ARIA Extensions in Tokens

When IdP issues tokens for user-bound agents, it embeds ARIA extensions based on active delegations:

{
  "aria_extensions": {
    "budget": { "unit": "usd", "amount": 25.0 },
    "max_steps": 5,
    "schema_pins": { "tool:flights": { "schema_hash": "sha256:..." } }
  }
}

πŸ“‹Access Reviews

Permissions drift over time. People change roles, projects end, but access often lingers. Access reviews are periodic certifications where managers verify that their team members' access is still appropriate. The Membership service tracks review campaigns, reviewer assignments, and certification decisions.

Access Review Workflow

  1. Campaign Creation: Admin creates a review campaign targeting specific roles, groups, or all access
  2. Reviewer Assignment: System assigns reviewers (typically managers) based on organizational hierarchy
  3. Certification: Reviewers approve, revoke, or flag access for each assignment
  4. Remediation: Revoked access is automatically removed; flagged items escalate
  5. Audit: Complete audit trail of all decisions with timestamps and justifications

Access Review API

# Create an access review campaign
curl -X POST https://membership.self.empowernow.ai/api/v1/access-reviews \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -d '{
    "name": "Q1 2026 Engineering Access Review",
    "scope": {
      "location_id": "engineering",
      "role_types": ["admin", "editor"]
    },
    "due_date": "2026-02-15T23:59:59Z",
    "reviewer_assignment": "manager"
  }'

# Certify an access item
curl -X POST https://membership.self.empowernow.ai/api/v1/access-reviews/{id}/certify \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -d '{
    "item_id": "assignment-123",
    "decision": "approve",
    "justification": "User still needs Editor role for current project"
  }'
πŸ’‘ Compliance Requirement

Many compliance frameworks (SOX, SOC2, HIPAA) require periodic access reviews. The Membership service provides the audit trail and automation needed for certification.

πŸ“–Cypher Query Cookbook

Here are battle-tested Cypher queries for common Membership operations. Bookmark this sectionβ€”you'll use these patterns repeatedly when debugging access issues or building reports.

Capability Check (User β†’ Agent)

// What can this agent do for this user?
MATCH (u:User {id: $user_id})-[:DELEGATES_TO {status: 'active'}]->
      (d:Delegation)-[:BINDS]->(:AIAgent {id: $agent_id})
MATCH (d)-[:HAS_CAPABILITY]->(c:Capability)
WHERE d.expires_at IS NULL OR d.expires_at > datetime()
RETURN collect(DISTINCT c.id) AS capabilities

Data Scope (Tenant Resolution)

// What tenants can this user access?
MATCH (u:User {id: $subject_id})-[:BELONGS_TO]->(t:Tenant)
OPTIONAL MATCH (u)-[:ASSIGNED_TO]->(:Project)-[:OWNED_BY]->(tp:Tenant)
WITH collect(DISTINCT t.id) + collect(DISTINCT tp.id) AS tids
RETURN {
  tenant_ids: [x IN tids WHERE x IS NOT NULL],
  row_filter_sql: CASE WHEN size(tids) > 0
    THEN 'tenant_id IN (\'' + apoc.text.join(tids, '\',\'') + '\')'
    ELSE '1=0' 
  END
} AS scope

Chain Eligibility (For Identity Chaining)

// What downstream tokens can be obtained for this tool?
MATCH (u:User {id: $user_id})-[:DELEGATES_TO {status: 'active'}]->
      (:Delegation)-[:BINDS]->(:AIAgent {id: $agent_id})
      -[:HAS_CAPABILITY]->(:Capability)-[:CAN_INVOKE]->(tool:Tool {id: $tool_id})
MATCH (tool)-[:REQUIRES]->(app:SaaSApp)
RETURN collect({
  audience: app.audience, 
  scopes: app.scopes
}) AS chain_eligibility

ReBAC Walk: Expense Approval

// Can John approve this expense in cost center CC-100?
MATCH (u:User {id: $user_id})-[:MEMBER_OF]->(:Group)
      -[:ASSIGNED_TO]->(br:BusinessRole {name: 'ExpenseApprover'})
MATCH (br)-[:SCOPED_TO]->(cc:CostCenter {id: $cost_center_id})
MATCH (r:ExpenseReport {id: $report_id})-[:BELONGS_TO]->(cc)
RETURN r.id AS report_id LIMIT 1

Find Orphan Nodes

// Find identities with no relationships (potential cleanup)
MATCH (n:Identity)
WHERE NOT (n)-[]-()
RETURN n.id, labels(n) AS type, n.name
LIMIT 50

Path Analysis

// Find shortest path between two identities
MATCH path = shortestPath(
  (a:Identity {id: $from_id})-[*..10]-(b:Identity {id: $to_id})
)
RETURN path, length(path) AS hops

πŸ“šKey API Endpoints Reference

The Membership API follows REST conventions with a focus on identity operations. These endpoints are your gateway to the identity graphβ€”whether you're building admin tools, integrating with HR systems, or debugging access issues.

Identity Management

EndpointMethodPurpose
/api/v1/identitiesGET/POSTList or create identities
/api/v1/identities/{id}GET/DELETEGet or delete identity
/api/v1/personsPOSTCreate person identity
/api/v1/ai-agentsPOSTCreate AI agent identity
/api/v1/identities/fulltext-searchGETFull-text identity search

Roles & Assignments

EndpointMethodPurpose
/api/v1/roles/{user_id}GETGet user's roles
/api/v1/roles/batchPOSTBatch role lookup
/api/v1/assignmentsPOST/PUTCreate or update assignment
/api/v1/assignments/bulkPOSTBulk create assignments
/api/v1/brlPOST/PUT/DELETEBusiness Role Location management

Delegations & AI Agents

EndpointMethodPurpose
/api/v1/delegationsPOST/GETManage delegations
/api/v1/agent/agents/{id}/controlPUT/GET/DELETEAgent control relationships
/api/v1/agent/agents/{id}/controllersGETList agent controllers

PIP Endpoints (for PDP)

EndpointPurpose
/api/v1/pip/membership/subject-enrichment?subject_id={id}Full subject enrichment
/api/v1/pip/membership/capabilitiesAgent capabilities for user
/api/v1/pip/membership/delegationsActive delegations with budget/steps
/api/v1/pip/membership/data-scopeTenant and row filtering
/api/v1/pip/membership/step-upMFA requirements
/api/v1/pip/membership/chain-eligibilityIdentity chaining audiences/scopes

Governance & Compliance

EndpointMethodPurpose
/api/v1/access-reviewsPOST/GETAccess review campaigns
/api/v1/resources/{id}/ownersPOST/GET/DELETEResource ownership
/api/v1/rtrs/assignPOSTRTR (rights) assignment
/api/v1/rtrs/assign-atPOSTLocation-scoped RTR assignment

Reports & Diagnostics

EndpointPurpose
/api/v1/reports/top-identities-by-accountsIdentities with most accounts
/api/v1/reports/access-outliersUnusual access patterns
/api/v1/node-label-countsCount nodes by label
/api/v1/relationship-type-countsCount relationships by type
/api/v1/orphan-node-countsNodes without relationships
/api/v1/shortest-pathPath between nodes
/metricsPrometheus metrics
/healthHealth check

πŸ”¬Hands-on Labs

Time to get your hands dirty with the identity graph. These labs will take you from basic queries to complex role resolution scenarios. Keep Neo4j Browser open alongside your terminal.
LAB 1 Explore the Identity Graph ⏱️ 10 minutes

Let's explore the structure of the identity graph in Neo4j.

1

Open Neo4j Browser:

Navigate to http://localhost:7474 and log in.

2

View the database schema:

CALL db.schema.visualization()

This shows all node types and their relationships.

3

Count entities by type:

MATCH (n) RETURN labels(n)[0] as type, count(*) as count ORDER BY count DESC
4

Visualize a sample of the graph:

MATCH (u:User)-[r]->(n) RETURN u, r, n LIMIT 25
βœ… Expected Results
  • Schema shows User, Role, Group, Location nodes
  • Relationships include HAS_ROLE, MEMBER_OF, INHERITS, BELONGS_TO
  • Visualization shows interconnected nodes
LAB 2 Trace Role Inheritance ⏱️ 15 minutes

Understand how roles inherit from each other and how that affects effective permissions.

1

Find the role hierarchy:

// Show role inheritance tree
MATCH path = (child:Role)-[:INHERITS*]->(parent:Role)
RETURN child.name as child_role, 
       [n in nodes(path) | n.name] as inheritance_path
ORDER BY length(path) DESC
2

Find all permissions a role grants (including inherited):

// Get admin role and all it inherits
MATCH (r:Role {name: 'admin'})-[:INHERITS*0..]->(inherited:Role)
RETURN DISTINCT inherited.name as role, inherited.permissions as permissions
3

Find a user's effective roles through all paths:

// Alice's roles: direct, via groups, via inheritance
MATCH (u:User {id: 'alice'})
OPTIONAL MATCH directPath = (u)-[:HAS_ROLE]->(directRole:Role)
OPTIONAL MATCH groupPath = (u)-[:MEMBER_OF*]->(g:Group)-[:HAS_ROLE]->(groupRole:Role)
OPTIONAL MATCH inheritPath = (directRole)-[:INHERITS*]->(inheritedRole:Role)
RETURN DISTINCT 
    COALESCE(directRole.name, groupRole.name, inheritedRole.name) as role,
    CASE 
        WHEN directRole IS NOT NULL THEN 'direct'
        WHEN groupRole IS NOT NULL THEN 'via group'
        ELSE 'inherited'
    END as source
πŸ€” Self-Check
  • How many levels deep is your role hierarchy?
  • Does Admin inherit from Editor? Does Editor inherit from Viewer?
  • What's the difference between direct and inherited roles?
LAB 3 Create and Query Delegations ⏱️ 15 minutes

Practice creating delegations via the API and see how they affect role resolution.

1

Get an access token:

ACCESS_TOKEN=$(curl -s -X POST https://idp.self.empowernow.ai/api/oidc/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials" \
  -d "client_id=bff-client" \
  -d "client_secret=YOUR_SECRET" \
  -d "scope=openid membership.write" | jq -r '.access_token')

echo $ACCESS_TOKEN
2

Create a delegation:

curl -X POST https://membership.self.empowernow.ai/api/v1/delegations \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -d '{
    "delegator_id": "bob",
    "delegate_id": "alice",
    "permission": "approve_expense",
    "starts_at": "2026-01-01T00:00:00Z",
    "expires_at": "2026-02-01T00:00:00Z",
    "reason": "Training lab exercise"
  }' | jq .
3

Verify the delegation in Neo4j:

// Find active delegations
MATCH (delegator:User)-[d:DELEGATES_TO]->(delegate:User)
WHERE d.expires_at > datetime()
RETURN delegator.id, delegate.id, d.permission, d.expires_at
4

Check Alice's effective permissions now include the delegation:

curl -s "https://membership.self.empowernow.ai/api/v1/pip/membership/subject-enrichment?subject_id=alice" \
  -H "Authorization: Bearer $ACCESS_TOKEN" | jq '.delegations'
βœ… Expected Results
  • Delegation created successfully with 201 response
  • Neo4j shows DELEGATES_TO relationship
  • PIP response includes the active delegation

πŸ”§Troubleshooting Membership Issues

Identity and access issues are among the most frustrating to debug because they often manifest as silent failures. Here are the patterns you'll encounter most often.
πŸ‘€ The Missing Role Case #1
πŸ“‹ Symptom

User can't access a resource. They insist they have the right role. PDP denies the request.

πŸ” Investigation
  • Check if the role assignment has a location scope that doesn't match the request
  • Verify the assignment hasn't expired
  • Check if it's a direct role or inherited through a group
// Check all assignments for a user
MATCH (u:User {id: 'alice'})-[r:HAS_ROLE]->(role:Role)
RETURN role.name, r.location, r.expires_at, r.assigned_at
βœ… Common Fixes
  • Reassign role with correct location scope
  • Extend expiration date if assignment was time-bounded
  • Add user to the correct group for inherited access
πŸ”„ The Stale Cache Case #2
πŸ“‹ Symptom

Role assignment was just created, but PDP still denies access. Direct Neo4j query shows the role exists.

πŸ” Investigation
  • Membership caches role lookups in Redis
  • PDP also caches authorization decisions
  • Both caches need to be invalidated or expire
βœ… Fix
  • Wait for cache TTL to expire (default: 5 minutes)
  • In development, restart the services to clear all caches
🌳 The Inheritance Loop Case #3
πŸ“‹ Symptom

Role queries are extremely slow or timeout. CPU usage on Neo4j spikes during role lookups.

πŸ” Investigation

Check for cycles in role inheritance or group membership:

// Find cycles in role inheritance
MATCH path = (r:Role)-[:INHERITS*]->(r)
RETURN path

// Find cycles in group membership
MATCH path = (g:Group)-[:MEMBER_OF*]->(g)
RETURN path
βœ… Fix
  • Remove the cyclic relationship
  • Redesign the hierarchy to be strictly acyclic
  • Add validation to prevent cycles during assignment

❓Knowledge Check

Test your understanding of the Membership service before the Week 2 assessment.
1 Why use a graph database for identity management instead of SQL? β–Ό

Identity is fundamentally about relationships: who belongs to what, who has which roles, who delegated to whom. In SQL, you'd need multiple JOIN operations to traverse these relationships, which becomes slow and complex.

In Neo4j:

  • Relationships are first-class citizens, not implied by foreign keys
  • Traversing N levels of hierarchy is O(1) per hop, not O(N) JOINs
  • Queries read like the patterns you're looking for
2 What's the difference between HAS_ROLE and MEMBER_OF relationships? β–Ό

HAS_ROLE: Direct assignment of a role to a user or group. Can have properties like location scope and expiration.

MEMBER_OF: Indicates a user belongs to a group, or a group belongs to another group. Used for organizational structure.

A user's effective roles come from: (1) direct HAS_ROLE, (2) HAS_ROLE inherited through MEMBER_OF, and (3) INHERITS relationships between roles.

3 What is location-scoped role assignment? β–Ό

A role assignment that only applies within a specific organizational unit (location). For example:

  • Alice is Admin at Engineering
  • Alice is Viewer at Marketing

When PDP evaluates, it considers the location context of the request. Alice trying to delete something in Marketing would only have Viewer permissions, not Admin.

4 How does PDP get user roles for authorization decisions? β–Ό

PDP uses a Policy Information Point (PIP) to fetch user context. The flow:

  1. PDP receives authorization request with user ID
  2. MembershipPIP calls /api/v1/pip/membership/subject-enrichment?subject_id={id}
  3. Membership returns effective roles, groups, delegations
  4. PDP evaluates policies with this enriched context

Results are cached to avoid calling Membership on every request.

5 What are delegations and when would you use them? β–Ό

Delegations are temporary permission transfers from one user to another. Use cases:

  • Vacation coverage: Manager delegates approval authority
  • Temporary assignments: Project lead role for a sprint
  • Emergency access: On-call engineer gets elevated permissions

Delegations have start/end dates, reasons, and are fully audited. Expired delegations are automatically excluded from PIP responses.

6 What does semantic search do in the Membership service? β–Ό

Semantic search uses AI embeddings to find identities, roles, and resources by meaning rather than exact keywords.

Example: "engineers who can approve production deployments" finds users who:

  • Have "engineer" in their title or group
  • Have roles that include deployment approval permissions
  • Have location scope that includes production

Uses OpenAI embeddings stored in Neo4j vector indexes, combined with full-text search for hybrid results.

7 What is role inheritance and how deep can it go? β–Ό

Role inheritance means a role automatically includes all permissions of its parent roles. Common patterns:

  • Admin β†’ inherits β†’ Editor β†’ inherits β†’ Viewer
  • Having Admin means you can do everything Editor and Viewer can do

Technically inheritance can be arbitrarily deep, but in practice keep it to 3-4 levels for maintainability. Deep hierarchies become hard to audit and reason about.

πŸ†Week 2 Assessment

Before moving to Week 3 (Plugin Development), verify you can:

  • Obtain an access token from IdP using any flow
  • Explain the difference between Access, Refresh, and ID tokens
  • Make a PDP evaluation request and interpret the response
  • Write a basic YAML policy rule
  • Query Neo4j for user roles and group memberships
  • Create a role assignment via the Membership API
  • Understand how Membership integrates with PDP as a PIP
  • Create and query delegations
πŸ“ Assessment Task

End-to-End Integration: Get a token from IdP β†’ Query Membership for user's effective roles β†’ Make a PDP authorization request with subject properties β†’ Verify the policy decision considers inherited roles and active delegations.

πŸ“Day 10 Checkpoint

  • Understand why Neo4j is ideal for identity relationships
  • Know all core entity types: Identity, Role, Group, Resource, Location
  • Can query Neo4j for users, roles, and hierarchies using Cypher
  • Understand location-scoped role assignments
  • Can create delegations and understand their lifecycle
  • Understand access reviews and governance workflows
  • Can use semantic search to find identities and roles
  • Understand how PDP uses Membership as a Policy Information Point
  • Completed Week 2 assessment