neo4j-security-skill

$npx mdskill add neo4j-contrib/neo4j-skills/neo4j-security-skill

Programmatically manage Neo4j users and roles

  • Create, alter, suspend, or drop Neo4j users as needed.
  • Grant or revoke role membership for existing Neo4j roles.
  • Inspect current user and role privileges using SHOW PRIVILEGES command.
  • Implement property-level access control to manage per-property read/write permissions.

SKILL.md

.github/skills/neo4j-security-skillView on GitHub ↗
---
name: neo4j-security-skill
description: Programmatic security management in Neo4j — RBAC/ABAC, user lifecycle (CREATE/ALTER/DROP USER),
  role lifecycle (CREATE/GRANT ROLE/DROP ROLE), privilege grants and denies (GRANT/DENY/REVOKE on graph,
  database, DBMS), property-level access control, sub-graph access control, SHOW PRIVILEGES inspection,
  and auth provider config reference (LDAP, OIDC/SSO). Use when an agent needs to manage users, roles,
  or privileges programmatically via Cypher on the system database. Does NOT handle Cypher query writing
  — use neo4j-cypher-skill. Does NOT handle cluster ops or backups — use neo4j-cli-tools-skill.
  Property-level security and ABAC require Enterprise Edition.
allowed-tools: Bash WebFetch
version: 1.0.1
---

## When to Use
- Creating, altering, suspending, or dropping users
- Creating roles, granting/revoking role membership
- Granting/denying/revoking graph, database, or DBMS privileges
- Inspecting current privileges (`SHOW PRIVILEGES`)
- Implementing property-level access control (read/write per property)
- Setting up ABAC rules against OIDC claims
- Referencing LDAP/SSO auth provider configuration

## When NOT to Use
- **Writing Cypher queries against application data** → `neo4j-cypher-skill`
- **Cluster ops, backups, server config** → `neo4j-cli-tools-skill`
- **Driver connection setup** → `neo4j-driver-*-skill`

---

## MCP Write Gate — MANDATORY

Before executing ANY of the following, show the planned command and wait for explicit confirmation:
- `CREATE USER` / `ALTER USER` / `DROP USER`
- `CREATE ROLE` / `DROP ROLE`
- `GRANT` / `DENY` / `REVOKE` (any privilege)
- `CREATE AUTH RULE` / `DROP AUTH RULE`

Never auto-execute privilege changes. Show exact Cypher, annotate impact, get "yes".

---

## Execution Context

All security Cypher runs against the **system** database:
```cypher
// Neo4j auto-routes CREATE/ALTER/SHOW USER|ROLE|PRIVILEGE to system
// If using cypher-shell: cypher-shell -d system
// If using driver: use database="system"
```

---

## 1. User Management

### Create user
```cypher
CREATE USER alice SET PASSWORD 'secret' CHANGE NOT REQUIRED;
// CHANGE REQUIRED (default): forces password change on first login
// CHANGE NOT REQUIRED: password valid immediately
// SET STATUS ACTIVE (default) | SUSPENDED
```

### Parameterised password (preferred in scripts)
```cypher
CREATE USER $username SET PASSWORD $password CHANGE NOT REQUIRED;
```

### Alter user
```cypher
ALTER USER alice SET PASSWORD $newPw CHANGE NOT REQUIRED;
ALTER USER alice SET STATUS SUSPENDED;          // lock account
ALTER USER alice SET STATUS ACTIVE;             // unlock
ALTER USER alice SET HOME DATABASE mydb;        // default db on connect
ALTER USER alice IF EXISTS SET PASSWORD $pw;    // safe if missing
```

### Show users
```cypher
SHOW USERS YIELD username, roles, passwordChangeRequired, suspended, homeDatabase
WHERE suspended = false
RETURN username, roles ORDER BY username;
```

### Drop user
```cypher
DROP USER alice IF EXISTS;
```

---

## 2. Role Management

### Create / drop role
```cypher
CREATE ROLE analyst;
CREATE ROLE analyst IF NOT EXISTS;
DROP ROLE analyst IF EXISTS;
```

### Assign / remove roles
```cypher
GRANT ROLE analyst TO alice;
GRANT ROLE analyst, writer TO alice, bob;   // bulk
REVOKE ROLE analyst FROM alice;
```

### Inspect roles
```cypher
SHOW ROLES YIELD role, member ORDER BY role;
SHOW ROLE analyst PRIVILEGES AS COMMANDS;   // returns runnable GRANT commands
SHOW POPULATED ROLES YIELD role;            // only roles with members
```

---

## 3. Privilege Decision Table

| Goal | Command |
|---|---|
| Allow db connection | `GRANT ACCESS ON DATABASE mydb TO analyst` |
| Read all graph data | `GRANT MATCH {*} ON GRAPH mydb ELEMENTS * TO analyst` |
| Read specific label | `GRANT MATCH {*} ON GRAPH mydb NODES Person TO analyst` |
| Read specific rel type | `GRANT MATCH {*} ON GRAPH mydb RELATIONSHIPS KNOWS TO analyst` |
| Read one property | `GRANT READ {email} ON GRAPH mydb NODES Person TO analyst` |
| Traverse but hide properties | `GRANT TRAVERSE ON GRAPH mydb NODES Person TO analyst` |
| Write (create/set) | `GRANT WRITE ON GRAPH mydb TO writer` |
| Create nodes only | `GRANT CREATE ON GRAPH mydb NODES Person TO writer` |
| Delete nodes only | `GRANT DELETE ON GRAPH mydb NODES Person TO writer` |
| Execute procedure | `GRANT EXECUTE PROCEDURE apoc.* TO analyst` |
| Execute function | `GRANT EXECUTE USER DEFINED FUNCTION apoc.* TO analyst` |
| All on one db | `GRANT ALL ON DATABASE mydb TO dba` |
| Full DBMS admin | `GRANT ALL ON DBMS TO dba` |
| Manage users | `GRANT USER MANAGEMENT ON DBMS TO secadmin` |
| Manage roles | `GRANT ROLE MANAGEMENT ON DBMS TO secadmin` |
| Schema changes | `GRANT CREATE ELEMENT TYPES ON DATABASE mydb TO schemaadmin` |

### DENY overrides GRANT
```cypher
// Analyst can read Person but NOT the ssn property
GRANT MATCH {*} ON GRAPH mydb NODES Person TO analyst;
DENY  READ {ssn} ON GRAPH mydb NODES Person TO analyst;
```

### REVOKE removes a specific grant or deny
```cypher
REVOKE GRANT READ {email} ON GRAPH mydb NODES Person FROM analyst;
REVOKE DENY  READ {ssn}   ON GRAPH mydb NODES Person FROM analyst;
REVOKE MATCH {*} ON GRAPH mydb NODES Person FROM analyst;  // removes both grant+deny
```

---

## 4. Common Role Patterns

### Read-only analyst
```cypher
CREATE ROLE analyst IF NOT EXISTS;
GRANT ACCESS            ON DATABASE mydb TO analyst;
GRANT MATCH {*}         ON GRAPH mydb ELEMENTS * TO analyst;
GRANT EXECUTE PROCEDURE apoc.* TO analyst;
```

### Write role (no admin)
```cypher
CREATE ROLE writer IF NOT EXISTS;
GRANT ACCESS  ON DATABASE mydb TO writer;
GRANT MATCH {*} ON GRAPH mydb ELEMENTS * TO writer;
GRANT WRITE   ON GRAPH mydb TO writer;
```

### Read-only on specific labels only
```cypher
CREATE ROLE limited_reader IF NOT EXISTS;
GRANT ACCESS    ON DATABASE mydb TO limited_reader;
GRANT TRAVERSE  ON GRAPH mydb ELEMENTS * TO limited_reader;      // can traverse
GRANT MATCH {*} ON GRAPH mydb NODES Person TO limited_reader;    // Person props visible
GRANT MATCH {*} ON GRAPH mydb NODES Company TO limited_reader;   // Company props visible
// Other labels: traversable but properties invisible
```

### DBA role (full admin)
```cypher
CREATE ROLE dba IF NOT EXISTS;
GRANT ALL ON DBMS     TO dba;
GRANT ALL ON DATABASE * TO dba;
```

---

## 5. Property-Level Access Control (Enterprise)

Restrict read access to individual properties:
```cypher
// Grant read on all Person props, then deny sensitive ones
GRANT MATCH {*}   ON GRAPH mydb NODES Person TO analyst;
DENY  READ {ssn, dateOfBirth} ON GRAPH mydb NODES Person TO analyst;
```

Property-based pattern matching (sub-graph access):
```cypher
// Only see Person nodes where classification = 'public'
GRANT MATCH {*} ON GRAPH mydb
  FOR (n:Person) WHERE n.classification = 'public'
  TO analyst;

// Block access to classified nodes
DENY MATCH {*} ON GRAPH mydb
  FOR (n) WHERE n.classification <> 'UNCLASSIFIED'
  TO regularUsers;
```

**Constraints:**
- `FOR` pattern applies to read privileges only — not write
- Each property-based privilege restricted by a single property
- Performance overhead scales with number of rules; `TRAVERSE` rules cost more than `READ`
- Ensure the property used for rules cannot be modified by the restricted role

---

## 6. ABAC — Attribute-Based Access Control (Enterprise + OIDC)

ABAC grants roles dynamically from JWT/OIDC claims rather than explicit `GRANT ROLE ... TO user`.

### Prerequisites
```
# neo4j.conf
dbms.security.abac.authorization_providers=<oidc-provider-alias>
```

### Create auth rule
```cypher
CREATE AUTH RULE salesRule
  SET CONDITION abac.oidc.user_attribute('department') = 'sales';

GRANT ROLE analyst TO AUTH RULE salesRule;
```

### Compound conditions
```cypher
CREATE OR REPLACE AUTH RULE seniorRule
  SET CONDITION abac.oidc.user_attribute('department') = 'engineering'
    AND abac.oidc.user_attribute('level') >= 5;

GRANT ROLE senior_engineer TO AUTH RULE seniorRule;
```

### Manage auth rules
```cypher
SHOW AUTH RULES YIELD ruleName, condition, roles;
ALTER AUTH RULE salesRule SET ENABLED false;     // disable without dropping
RENAME AUTH RULE salesRule TO salesDeptRule;
DROP AUTH RULE salesDeptRule;
REVOKE ROLE analyst FROM AUTH RULE salesRule;
```

Native users [2026.06+]: tag native DB users and match tags in rules via `abac.native.user_tags()` — no OIDC required:
```cypher
CREATE AUTH RULE nativeSalesRule
  SET CONDITION 'sales' IN abac.native.user_tags();
GRANT ROLE analyst TO AUTH RULE nativeSalesRule;
```

**Notes:**
- Missing claims evaluate to NULL → rule condition false → role not granted
- Rules apply immediately to existing sessions when claims are already loaded
- OIDC claims via `abac.oidc.user_attribute()`; native user tags via `abac.native.user_tags()` [2026.06+]; LDAP not supported
- User-defined functions rejected in PBAC property-rule predicates [2026.06+]

---

## 7. SHOW PRIVILEGES Patterns

```cypher
// All privileges in the system
SHOW PRIVILEGES YIELD *;

// Privileges for a specific user (as runnable commands)
SHOW USER alice PRIVILEGES AS COMMANDS;

// Privileges for a specific role
SHOW ROLE analyst PRIVILEGES YIELD privilege, action, resource, graph, segment;

// Find who has access to a database
SHOW PRIVILEGES YIELD *
WHERE graph = 'mydb'
RETURN role, action, resource, segment ORDER BY role;

// Find all DENY rules
SHOW PRIVILEGES YIELD *
WHERE access = 'DENIED'
RETURN role, action, resource, segment;
```

---

## 8. Built-in Roles (do not drop)

| Role | Scope |
|---|---|
| `admin` | Full DBMS + all databases |
| `architect` | Schema changes + write on all databases |
| `publisher` | Write on all databases |
| `editor` | Write excluding schema changes |
| `reader` | Read-only on all databases |
| `public` | All users implicitly; default home database access |

Assign built-in roles: `GRANT ROLE reader TO alice;`

---

## 9. Auth Provider Config Reference (operational — not Cypher)

### Native (default)
```
dbms.security.auth_enabled=true
dbms.security.auth_max_failed_attempts=3    # lockout threshold
```

### LDAP
```
dbms.security.auth_provider=ldap
dbms.security.ldap.host=ldap://ldap.example.com
dbms.security.ldap.authentication.mechanism=simple
dbms.security.ldap.authentication.user_dn_template=uid={0},ou=users,dc=example,dc=com
dbms.security.ldap.authorization.group_membership_attributes=memberOf
dbms.security.ldap.authorization.group_to_role_mapping=\
  "cn=analysts,ou=groups,dc=example,dc=com" = analyst;\
  "cn=admins,ou=groups,dc=example,dc=com"   = admin
```

### OIDC / SSO (Okta, Auth0, Entra ID)
```
dbms.security.oidc.<alias>.display_name=Okta
dbms.security.oidc.<alias>.auth_flow=pkce
dbms.security.oidc.<alias>.well_known_discovery_uri=https://example.okta.com/.well-known/openid-configuration
dbms.security.oidc.<alias>.audience=neo4j
dbms.security.oidc.<alias>.claims.username=email
dbms.security.oidc.<alias>.claims.groups=groups
dbms.security.oidc.<alias>.authorization.group_to_role_mapping=\
  "neo4j-analysts" = analyst;\
  "neo4j-admins"   = admin
```

Config changes require **server restart**. Roles referenced in mappings must exist in Neo4j (native or created via Cypher).

---

## Checklist — New Role Setup

- [ ] Determine required operations: read / write / admin
- [ ] Identify target database(s) and graph scope (all labels vs specific)
- [ ] Identify any properties that must be hidden (→ DENY READ)
- [ ] Create role: `CREATE ROLE ... IF NOT EXISTS`
- [ ] Grant ACCESS on database
- [ ] Grant MATCH / TRAVERSE / WRITE as needed
- [ ] Apply DENY for restricted properties
- [ ] Run `SHOW ROLE ... PRIVILEGES AS COMMANDS` to verify
- [ ] Assign to users: `GRANT ROLE ... TO ...`
- [ ] Test with `SHOW USER ... PRIVILEGES AS COMMANDS`

Full privilege syntax → [references/privilege-reference.md](references/privilege-reference.md)

More from neo4j-contrib/neo4j-skills

SkillDescription
neo4j-agent-memory-skillAuthoritative reference for the neo4j-agent-memory Python package — a graph-native memory system for AI agents built on Neo4j — and for the hosted service (NAMS) at memory.neo4jlabs.com. Use this skill whenever the user mentions neo4j-agent-memory, agent memory with Neo4j, context graphs, the POLE+O model, MemoryClient/MemorySettings, the memory MCP server, or any of the framework integrations (LangChain, PydanticAI, CrewAI, AWS Strands, Google ADK, Microsoft Agent Framework, OpenAI Agents, LlamaIndex). Also use when the user mentions the hosted service at memory.neo4jlabs.com, NAMS, the Neo4j Agent Memory Service, the `nams_` API key prefix, or the hosted MCP endpoint. Also use when writing documentation, blog posts, tutorials, PRDs, or code samples for the project, when comparing agent memory approaches, or when positioning graph-native memory against vector-only approaches — even if the user doesn't explicitly name the package.
neo4j-aura-agent-skillManages Neo4j Aura Agents via the v2beta1 REST API — create, list, get, update, delete,
neo4j-aura-graph-analytics-skillServerless Aura Graph Analytics (AGA) GDS Sessions — covers GdsSessions,
neo4j-aura-provisioning-skillProvisions and manages Neo4j Aura instances via CLI (aura-cli v1.7+) or REST API.
neo4j-cli-tools-skillUse when working with Neo4j command-line tools — neo4j-cli (modern unified
neo4j-cypher-skillGenerates, optimizes, and validates Cypher 25 queries for Neo4j 2025.x and 2026.x.
neo4j-document-import-skillIngests unstructured and semi-structured documents into Neo4j as a knowledge graph.
neo4j-driver-dotnet-skillNeo4j .NET Driver v6 — IDriver lifecycle, DI registration (singleton), ExecutableQuery
neo4j-driver-go-skillCovers the Neo4j Go Driver v6 — driver lifecycle, ExecuteQuery, managed and
neo4j-driver-java-skillNeo4j Java Driver v6 — driver lifecycle, Maven/Gradle setup, executableQuery,