Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions modules/ROOT/content-nav.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
*** xref:authentication-and-authorization/configuration.adoc[]
*** xref:authentication-and-authorization/authentication.adoc[]
*** xref:authentication-and-authorization/authorization.adoc[]
*** xref:authentication-and-authorization/impersonation-and-user-switching.adoc[]

** xref:introspector.adoc[Introspector]

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
= Impersonation and user switching

Impersonation and user switching are features of the Neo4j database and driver which allow for query execution in a different context to the initial connection.

== Impersonation

Impersonation still authenticates with the database as the original configured user, but runs the query in the context of an impersonated user.
When impersonating a user, the query is run within the complete security context of the impersonated user and not the authenticated user (home database, permissions, etc.).

An example of how to impersonate a different user per request can be found below. In this example, the user to impersonate is taken from a HTTP header `User`:

.TypeScript
[%collapsible]
====
[source, typescript, indent=0]
----
import { ApolloServer } from "@apollo/server";
import { startStandaloneServer } from "@apollo/server/standalone";
import { Neo4jGraphQL, Neo4jGraphQLContext } from "@neo4j/graphql";
import neo4j from "neo4j-driver";

const typeDefs = `#graphql
type Movie {
title: String!
}
`;

const driver = neo4j.driver(
"neo4j://localhost:7687",
neo4j.auth.basic("neo4j", "password")
);

const neo4jgraphql = new Neo4jGraphQL({
typeDefs,
driver,
});

const schema = await neo4jgraphql.getSchema();

const server = new ApolloServer<Neo4jGraphQLContext>({
schema,
});

const { url } = await startStandaloneServer(server, {
// Your async context function should async and return an object
context: async ({ req }) => ({
sessionConfig: {
impersonatedUser: req.headers.user,
},
}),
});

console.log(`🚀 Server ready at: ${url}`);
----
====

.JavaScript
[%collapsible]
====
[source, javascript, indent=0]
----
import { ApolloServer } from "@apollo/server";
import { startStandaloneServer } from "@apollo/server/standalone";
import { Neo4jGraphQL } from "@neo4j/graphql";
import neo4j from "neo4j-driver";

const typeDefs = `#graphql
type Movie {
title: String!
}
`;

const driver = neo4j.driver(
"neo4j://localhost:7687",
neo4j.auth.basic("neo4j", "password")
);

const neo4jgraphql = new Neo4jGraphQL({
typeDefs,
driver,
});

const schema = await neo4jgraphql.getSchema();

const server = new ApolloServer({
schema,
});

const { url } = await startStandaloneServer(server, {
// Your async context function should async and return an object
context: async ({ req }) => ({
sessionConfig: {
impersonatedUser: req.headers.user,
},
}),
});

console.log(`🚀 Server ready at: ${url}`);
----
====

== User switching

User switching completely switches the user authenticating with the database for the given session, without the performance cost of instantiating an entire new driver instance.

An example of configuring user switching on a per request basis can be found in the example below. Note that the username and password are provided in HTTP headers `User` and `Password`, but this would not be recommended for production use:

.TypeScript
[%collapsible]
====
[source, typescript, indent=0]
----
import { ApolloServer } from "@apollo/server";
import { startStandaloneServer } from "@apollo/server/standalone";
import { Neo4jGraphQL, Neo4jGraphQLContext } from "@neo4j/graphql";
import neo4j from "neo4j-driver";

const typeDefs = `#graphql
type Movie {
title: String!
}
`;

const driver = neo4j.driver(
"neo4j://localhost:7687",
neo4j.auth.basic("neo4j", "password")
);

const neo4jgraphql = new Neo4jGraphQL({
typeDefs,
driver,
});

const schema = await neo4jgraphql.getSchema();

const server = new ApolloServer<Neo4jGraphQLContext>({
schema,
});

const { url } = await startStandaloneServer(server, {
// Your async context function should async and return an object
context: async ({ req }) => ({
sessionConfig: {
auth: neo4j.auth.basic(req.headers.user, req.headers.password),
},
}),
});

console.log(`🚀 Server ready at: ${url}`);
----
====

.JavaScript
[%collapsible]
====
[source, javascript, indent=0]
----
import { ApolloServer } from "@apollo/server";
import { startStandaloneServer } from "@apollo/server/standalone";
import { Neo4jGraphQL } from "@neo4j/graphql";
import neo4j from "neo4j-driver";

const typeDefs = `#graphql
type Movie {
title: String!
}
`;

const driver = neo4j.driver(
"neo4j://localhost:7687",
neo4j.auth.basic("neo4j", "password")
);

const neo4jgraphql = new Neo4jGraphQL({
typeDefs,
driver,
});

const schema = await neo4jgraphql.getSchema();

const server = new ApolloServer({
schema,
});

const { url } = await startStandaloneServer(server, {
// Your async context function should async and return an object
context: async ({ req }) => ({
sessionConfig: {
auth: neo4j.auth.basic(req.headers.user, req.headers.password),
},
}),
});

console.log(`🚀 Server ready at: ${url}`);
----
====