From b57242c6b9d78de9429976f3d23e51c95d525bbc Mon Sep 17 00:00:00 2001 From: Richard Sill Date: Mon, 26 Aug 2024 15:54:57 +0200 Subject: [PATCH 01/12] reordered overview page links to match navigation --- modules/ROOT/pages/security/index.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/ROOT/pages/security/index.adoc b/modules/ROOT/pages/security/index.adoc index 49603558..f5f81197 100644 --- a/modules/ROOT/pages/security/index.adoc +++ b/modules/ROOT/pages/security/index.adoc @@ -6,9 +6,9 @@ auth/authorization/allow.adoc, auth/authorization/bind.adoc, auth/authorization/ auth/authorization/where.adoc, authentication-and-authorization/index.adoc +* xref::/security/configuration.adoc[Configuration] - Instructions to set up instantiation. * xref::/security/authentication.adoc[Authentication] - Explicit authentication, configured using the `@authentication` directive. * xref::/security/authorization.adoc[Authorization] - Authorization rules set using the `@authorization` directive. -* xref::/security/subscriptions-authorization.adoc[Subscriptions authorization] - Authorization rules for subscriptions set using the `@subscriptionsAuthorization` directive. -* xref::/security/configuration.adoc[Configuration] - Instructions to set up instantiation. +* xref::/security/subscriptions-authorization.adoc[Subscriptions authorization] - Authorization rules for subscriptions set using the `@subscriptionsAuthorization` directive. * xref::/security/impersonation-and-user-switching.adoc[Impersonation and user switching] - How to set up impersonation and user switching features. * xref::/security/operations.adoc[Operations] - Reference on GraphQL queries and how each location in each query triggers the evaluation of different authentication/authorization rules. From 5ddefe44374e0f1148741e91c859dacbc2230a3a Mon Sep 17 00:00:00 2001 From: Richard Sill Date: Tue, 27 Aug 2024 09:56:20 +0200 Subject: [PATCH 02/12] some changes to the configuration page --- modules/ROOT/pages/directives/index.adoc | 4 +- .../ROOT/pages/security/configuration.adoc | 149 +++++++++++------- 2 files changed, 91 insertions(+), 62 deletions(-) diff --git a/modules/ROOT/pages/directives/index.adoc b/modules/ROOT/pages/directives/index.adoc index a8929ad3..8d30fa4a 100644 --- a/modules/ROOT/pages/directives/index.adoc +++ b/modules/ROOT/pages/directives/index.adoc @@ -40,10 +40,10 @@ a| Required to differentiate interfaces that are used for relationship propertie | xref::/security/authorization.adoc[`@authorization`] | Specifies authorization rules for queries and mutations on the type. -| xref::/security/configuration.adoc#authentication-and-authorization-jwt[`@jwt`] +| xref::/security/configuration.adoc#_the_jwt_directive[`@jwt`] | Configures the JWT authentication and authorization filters to include additional JWT claims. -| xref::/security/configuration.adoc#_nested_claims[`@jwtClaim`] +| xref::/security/configuration.adoc#_the_jwtclaim_directive[`@jwtClaim`] | Used in combination with `@jwt`. Configures the JWT authentication and authorization filters to include an additional JWT claim which is either nested or using special characters not supported by GraphQL. diff --git a/modules/ROOT/pages/security/configuration.adoc b/modules/ROOT/pages/security/configuration.adoc index c392d997..ea731f24 100644 --- a/modules/ROOT/pages/security/configuration.adoc +++ b/modules/ROOT/pages/security/configuration.adoc @@ -1,16 +1,28 @@ = Configuration :description: This page describes how to configure authentication and authorization features in the Neo4j GraphQL Library. +The Neo4j GraphQL Library uses JSON Web Token (JWT) authentication. +JWTs are tokens containing claims or statements about the user or client making the request. +These claims can include information such as the user's ID or roles. + +When a user or client logs in to the API, the API generates a JWT and returns it to the client. +The client then includes the JWT with each subsequent request to the API. +The API verifies the JWT and returns the requested data if the JWT is valid. + +// ^ is this paragraph accurate? + == Instantiation -The Neo4j GraphQL Library can accept JSON Web Tokens via two mechanisms: +The Neo4j GraphQL Library can accept two types of JWTs: * Encoded JWTs in the `token` field of the request context. * Decoded JWTs in the `jwt` field of the request context. -If using the former, the library will need to be configured with a key to decode and verify the token. +=== Encoded JWTs -The following code block demonstrates using Apollo Server, extracting the `Authorization` header from the request, and putting it into the appropriate context field: +To use encoded JWTs, the library must to be configured with a key to decode and verify the tokens. + +The following code block uses Apollo Server, extracts the `Authorization` header from the request and puts it in the appropriate context field: [source, typescript, indent=0] ---- @@ -28,10 +40,14 @@ const { url } = await startStandaloneServer(server, { Optionally, if a custom decoding mechanism is required, that same header can be decoded and the resulting JWT payload put into the `jwt` field of the context. -=== Symmetric secret +// ^ Can we show the above in a code listing? + +==== Symmetric secret To configure the library with a symmetric secret (e.g. "secret"), the following instantiation is required: +// ^ What is a symmetric secret? What is its purpose? + [source, typescript, indent=0] ---- new Neo4jGraphQL({ @@ -44,9 +60,11 @@ new Neo4jGraphQL({ }); ---- -=== JWKS endpoint +==== JWKS endpoint -To configure the library to verify tokens against a JWKS endpoint, "https://www.myapplication.com/.well-known/jwks.json", the following instantiation is required: +To configure the library to verify tokens against a JWKS endpoint, for example "https://www.myapplication.com/.well-known/jwks.json", the following instantiation is required: + +// ^ What is the purpose? [source, typescript, indent=0] ---- @@ -62,14 +80,66 @@ new Neo4jGraphQL({ }); ---- -[[authentication-and-authorization-jwt]] -== JWT +==== Passing in encoded JWTs + +// This was at the end of the file, I thought it could be moved here instead. What about decoded JWTs? + +To pass in an encoded JWT, use the token field of the context. +When using Apollo Server, extract the authorization header into the token property of the context: + +[source, javascript, indent=0] +---- +const server = new ApolloServer({ + schema, +}); + +await startStandaloneServer(server, { + context: async ({ req }) => ({ token: req.headers.authorization }), +}); +---- + +For example, a HTTP request with the following `authorization` header should look like this: + +[source] +---- +POST / HTTP/1.1 +authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJyb2xlcyI6WyJ1c2VyX2FkbWluIiwicG9zdF9hZG1pbiIsImdyb3VwX2FkbWluIl19.IY0LWqgHcjEtOsOw60mqKazhuRFKroSXFQkpCtWpgQI +content-type: application/json +---- + +Alternatively, you can pass a key `jwt` of type `JwtPayload` into the context, which has the following definition: + +[source, typescript, indent=0] +---- +// standard claims https://datatracker.ietf.org/doc/html/rfc7519#section-4.1 +interface JwtPayload { + [key: string]: any; + iss?: string | undefined; + sub?: string | undefined; + aud?: string | string[] | undefined; + exp?: number | undefined; + nbf?: number | undefined; + iat?: number | undefined; + jti?: string | undefined; +} +---- + +[WARNING] +Do not pass in the header or the signature. + +=== Decoded JWTs + +// What could be added here? + +== Adding JWT claims By default, filtering is available on https://www.rfc-editor.org/rfc/rfc7519#section-4.1[the registered claim names] in the JWT specification. Filtering can be configured for additional JWT claims using the `@jwt` directive and, in some circumstances, the `@jwtClaim` directive. -If you configure an additional `roles` claim, which is an array of strings located at the root of the JWT payload, the following must be added to the type definitions: +=== The `@jwt` directive + +If you configure an additional `roles` claim, which is an array of strings located at the root of the JWT payload, add the following to the type definitions: [source, graphql, indent=0] ---- @@ -78,11 +148,12 @@ type JWT @jwt { } ---- -Note that the type name here, `JWT`, is not required, and this can have any name as long as it is decorated with the `@jwt` directive. +Note that the type name `JWT` is not required. +You can use any name as long as it is decorated with the `@jwt` directive. -=== Nested claims +=== The `@jwtClaim` directive -If the previous `roles` claim is not located at the JWT payload root, but instead in a nested location, for example: +A `roles` claim is not necessarily located at the JWT payload root, but can instead be in a nested location, for example: [source, json, indent=0] ---- @@ -94,7 +165,9 @@ If the previous `roles` claim is not located at the JWT payload root, but instea } ---- -This needs to be configured using the `@jwtClaim` directive: +// ^ why is this a nested location? can we show the nesting? + +In this case, use the `@jwtClaim` directive: [source, graphql, indent=0] ---- @@ -103,7 +176,7 @@ type JWT @jwt { } ---- -Additionally, if this nested location contains any `.` characters in the path, for example: +Additionally, the nested location may contain `.` characters in the path, for example: [source, json, indent=0] ---- @@ -115,7 +188,7 @@ Additionally, if this nested location contains any `.` characters in the path, f } ---- -These characters need to be escaped: +Escape these characters: [source, graphql, indent=0] ---- @@ -126,50 +199,6 @@ type JWT @jwt { [NOTE] ==== -The seemingly excessive escaping is required to doubly escape: once for GraphQL and once for `dot-prop`, which is used under the hood to resolve the path. +This way of escaping is necessary to escape twice: once for GraphQL and once for `dot-prop`, which is used under the hood to resolve the path. ==== -== Passing in JWTs - -To pass in an encoded JWT, you must use the token field of the context. -When using Apollo Server, extract the authorization header into the token property of the context as follows: - -[source, javascript, indent=0] ----- -const server = new ApolloServer({ - schema, -}); - -await startStandaloneServer(server, { - context: async ({ req }) => ({ token: req.headers.authorization }), -}); ----- - -For example, a HTTP request with the following `authorization` header should look like this: - -[source] ----- -POST / HTTP/1.1 -authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJyb2xlcyI6WyJ1c2VyX2FkbWluIiwicG9zdF9hZG1pbiIsImdyb3VwX2FkbWluIl19.IY0LWqgHcjEtOsOw60mqKazhuRFKroSXFQkpCtWpgQI -content-type: application/json ----- - -Alternatively, you can pass a key `jwt` of type `JwtPayload` into the context, which has the following definition: - -[source, typescript, indent=0] ----- -// standard claims https://datatracker.ietf.org/doc/html/rfc7519#section-4.1 -interface JwtPayload { - [key: string]: any; - iss?: string | undefined; - sub?: string | undefined; - aud?: string | string[] | undefined; - exp?: number | undefined; - nbf?: number | undefined; - iat?: number | undefined; - jti?: string | undefined; -} ----- - -[WARNING] -_Do not_ pass in the header or the signature. From 381f006fa408af7d6f5b49d61d24e84d6810aa91 Mon Sep 17 00:00:00 2001 From: Richard Sill Date: Tue, 27 Aug 2024 15:22:28 +0200 Subject: [PATCH 03/12] some adjustments, some answered questions --- .../ROOT/pages/security/configuration.adoc | 20 +++++-------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/modules/ROOT/pages/security/configuration.adoc b/modules/ROOT/pages/security/configuration.adoc index ea731f24..59853c72 100644 --- a/modules/ROOT/pages/security/configuration.adoc +++ b/modules/ROOT/pages/security/configuration.adoc @@ -5,12 +5,9 @@ The Neo4j GraphQL Library uses JSON Web Token (JWT) authentication. JWTs are tokens containing claims or statements about the user or client making the request. These claims can include information such as the user's ID or roles. -When a user or client logs in to the API, the API generates a JWT and returns it to the client. -The client then includes the JWT with each subsequent request to the API. +A JWT can be obtained from an authentication service and is then included in an API request. The API verifies the JWT and returns the requested data if the JWT is valid. -// ^ is this paragraph accurate? - == Instantiation The Neo4j GraphQL Library can accept two types of JWTs: @@ -21,7 +18,6 @@ The Neo4j GraphQL Library can accept two types of JWTs: === Encoded JWTs To use encoded JWTs, the library must to be configured with a key to decode and verify the tokens. - The following code block uses Apollo Server, extracts the `Authorization` header from the request and puts it in the appropriate context field: [source, typescript, indent=0] @@ -46,8 +42,6 @@ Optionally, if a custom decoding mechanism is required, that same header can be To configure the library with a symmetric secret (e.g. "secret"), the following instantiation is required: -// ^ What is a symmetric secret? What is its purpose? - [source, typescript, indent=0] ---- new Neo4jGraphQL({ @@ -62,9 +56,7 @@ new Neo4jGraphQL({ ==== JWKS endpoint -To configure the library to verify tokens against a JWKS endpoint, for example "https://www.myapplication.com/.well-known/jwks.json", the following instantiation is required: - -// ^ What is the purpose? +To configure the library to verify tokens against a JSON Web Key Set (JWKS) endpoint, for example "https://www.example.com/.well-known/jwks.json", the following instantiation is required: [source, typescript, indent=0] ---- @@ -82,7 +74,7 @@ new Neo4jGraphQL({ ==== Passing in encoded JWTs -// This was at the end of the file, I thought it could be moved here instead. What about decoded JWTs? +// What about decoded JWTs? To pass in an encoded JWT, use the token field of the context. When using Apollo Server, extract the authorization header into the token property of the context: @@ -153,7 +145,7 @@ You can use any name as long as it is decorated with the `@jwt` directive. === The `@jwtClaim` directive -A `roles` claim is not necessarily located at the JWT payload root, but can instead be in a nested location, for example: +A `roles` claim is not necessarily located at the JWT payload root, but can instead be in a nested location, for example under `myApplication`: [source, json, indent=0] ---- @@ -165,8 +157,6 @@ A `roles` claim is not necessarily located at the JWT payload root, but can inst } ---- -// ^ why is this a nested location? can we show the nesting? - In this case, use the `@jwtClaim` directive: [source, graphql, indent=0] @@ -199,6 +189,6 @@ type JWT @jwt { [NOTE] ==== -This way of escaping is necessary to escape twice: once for GraphQL and once for `dot-prop`, which is used under the hood to resolve the path. +The `path` must be escaped twice: once for GraphQL and once for `dot-prop`, which is used under the hood to resolve the path. ==== From c1c90c1e196009072114b1065670c0eda94bf6ba Mon Sep 17 00:00:00 2001 From: Richard Sill Date: Tue, 27 Aug 2024 15:34:00 +0200 Subject: [PATCH 04/12] added an admonition, made it clearer that @jwtClaim is used alongside @jwt --- modules/ROOT/pages/security/configuration.adoc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/ROOT/pages/security/configuration.adoc b/modules/ROOT/pages/security/configuration.adoc index 59853c72..af5a328d 100644 --- a/modules/ROOT/pages/security/configuration.adoc +++ b/modules/ROOT/pages/security/configuration.adoc @@ -140,6 +140,7 @@ type JWT @jwt { } ---- +[NOTE] Note that the type name `JWT` is not required. You can use any name as long as it is decorated with the `@jwt` directive. @@ -157,7 +158,7 @@ A `roles` claim is not necessarily located at the JWT payload root, but can inst } ---- -In this case, use the `@jwtClaim` directive: +In this case, use the `@jwtClaim` directive alongside the `@jwt` directive: [source, graphql, indent=0] ---- From 4cd684ed9b7328eddb285a9bd91ae077e07a4774 Mon Sep 17 00:00:00 2001 From: Richard Sill Date: Tue, 3 Sep 2024 14:12:26 +0200 Subject: [PATCH 05/12] review suggestions --- .../ROOT/pages/security/configuration.adoc | 26 +++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/modules/ROOT/pages/security/configuration.adoc b/modules/ROOT/pages/security/configuration.adoc index af5a328d..a256ce7e 100644 --- a/modules/ROOT/pages/security/configuration.adoc +++ b/modules/ROOT/pages/security/configuration.adoc @@ -17,7 +17,7 @@ The Neo4j GraphQL Library can accept two types of JWTs: === Encoded JWTs -To use encoded JWTs, the library must to be configured with a key to decode and verify the tokens. +To use encoded JWTs, the library can be configured with a key to decode and verify the tokens. The following code block uses Apollo Server, extracts the `Authorization` header from the request and puts it in the appropriate context field: [source, typescript, indent=0] @@ -36,7 +36,7 @@ const { url } = await startStandaloneServer(server, { Optionally, if a custom decoding mechanism is required, that same header can be decoded and the resulting JWT payload put into the `jwt` field of the context. -// ^ Can we show the above in a code listing? +Alternatively, you can decode a token via a xref:#_jwks_endpoint[]. ==== Symmetric secret @@ -74,8 +74,6 @@ new Neo4jGraphQL({ ==== Passing in encoded JWTs -// What about decoded JWTs? - To pass in an encoded JWT, use the token field of the context. When using Apollo Server, extract the authorization header into the token property of the context: @@ -119,9 +117,27 @@ interface JwtPayload { [WARNING] Do not pass in the header or the signature. + === Decoded JWTs -// What could be added here? +A decoded JWT is passed to the context in a similar way that an encoded JWT is. +However, instead of using a token, it uses the `jwt` field: + +[source, typescript, indent=0] +---- +const jwt = customImplementation(); + +const { url } = await startStandaloneServer(server, { + listen: { port: 4000 }, + context: async ({ req }) => ({ + jwt: jwt, + }), +}); +---- + +`customImplementation` is a placeholder for a function that provides a decoded JWT. +Using `jwt` instead of `token` in the `context` informs the Neo4jGraphQL library that it doesn't need to decode it. + == Adding JWT claims From 965836409e373f65f78f9e22a571033b5c3efd32 Mon Sep 17 00:00:00 2001 From: Richard Sill Date: Wed, 4 Sep 2024 16:44:43 +0200 Subject: [PATCH 06/12] changes to the authentication page --- .../ROOT/pages/security/authentication.adoc | 110 ++++++++++-------- 1 file changed, 62 insertions(+), 48 deletions(-) diff --git a/modules/ROOT/pages/security/authentication.adoc b/modules/ROOT/pages/security/authentication.adoc index 3ddedfc7..df10b84f 100644 --- a/modules/ROOT/pages/security/authentication.adoc +++ b/modules/ROOT/pages/security/authentication.adoc @@ -1,13 +1,62 @@ = Authentication :description: This page describes how to set up authentication features in the Neo4j GraphQL Library. -Explicit authentication, configured using the `@authentication` directive, is only ever evaluated -during Cypher translation time, and unauthenticated requests with queries requiring authentication -will never reach the database. +The GraphQL Library offers the `@authentication` directive to configure authentication for certain operations and for different parts of your schema. -== Configuration +[NOTE] +Explicit authentication, configured with the `@authentication` directive, is only ever evaluated during Cypher translation time, and unauthenticated requests with queries requiring authentication never reach the database. -Authentication can be configured for an entire type, for example, the type `User`: +== Operations + +Authentication can be configured to only be validated on certain operations: + +* `CREATE` +* `READ` +* `AGGREGATE` +* `UPDATE` +* `DELETE` +* `CREATE_RELATIONSHIP` +* `DELETE_RELATIONSHIP` +* `SUBSCRIBE` + + +For instance, to only require authentication for the update or deletion of a user: + +[source, graphql, indent=0] +---- +type User @authentication(operations: [UPDATE, DELETE]) { + id: ID! + name: String! + password: String! +} +---- + +[NOTE] +If there is no `operations` argument with a list of operations, the GraphQL Library treats the authentication configuration as if the full list of operations had been provided. + + +== Scope + + +=== Global authentication + +Athentication can be applied to the entire schema. +This ensures authentication is checked for every matching request. + +Extend the schema: + +[source, graphql, indent=0] +---- +extend schema @authentication +---- + +The `operations` and `jwt` arguments can also be used when the directive is applied to a schema extension. + +// ^ should we add links or provide examples? + +=== Authentication for types + +Authentication can be configured for an entire type: [source, graphql, indent=0] ---- @@ -18,7 +67,7 @@ type User @authentication { } ---- -Authentication will thus be validated when any of the following operations are _attempted_: +With this configuration, authentication is validated when any of the following operations are _attempted_: * *Create*: `createUsers` mutation, `create`, or `connectOrCreate` nested operation via a related type. * *Read*: `users`, `usersConnection`, `usersAggregate` query, or access via related type. @@ -28,7 +77,10 @@ Authentication will thus be validated when any of the following operations are _ * *Delete relationship*: `disconnect` nested operation via a related type. * *Subscribe*: all subscription operations related to type `User`. -Additionally, the directive can be configured on a per-field basis, for example: + +=== Authentication for fields + +Authentication can be configured on a per-field basis, for example: [source, graphql, indent=0] ---- @@ -39,37 +91,13 @@ type User { } ---- -This will only be evaluated in the following circumstances: +This is only evaluated under the following circumstances: * The `password` field is set on either `create` or `update`. * The `password` field is present in a selection set. -=== Operations - -Authentication can be configured to only be validated on certain operations: - -* `CREATE` -* `READ` -* `AGGREGATE` -* `UPDATE` -* `DELETE` -* `CREATE_RELATIONSHIP` -* `DELETE_RELATIONSHIP` -* `SUBSCRIBE` - -For instance, to only require authentication for the update or deletion of a user: - -[source, graphql, indent=0] ----- -type User @authentication(operations: [UPDATE, DELETE]) { - id: ID! - name: String! - password: String! -} ----- - -=== Additional verification +== Additional verification Additional checks against JWT claims can be performed together with authentication. For instance, if it was a requirement that only users with the `admin` role can delete users: @@ -81,18 +109,4 @@ type User @authentication(operations: [DELETE], jwt: { roles_INCLUDES: "admin" } name: String! password: String! } ----- - -== Global authentication - -Additionally, authentication can be applied to the entire schema. -This ensures authentication is checked for every matching request. - -This is done via extending the schema: - -[source, graphql, indent=0] ----- -extend schema @authentication ----- - -The `operations` and `jwt` arguments can also be used when the directive is applied to a schema extension. +---- \ No newline at end of file From c6fdc974eba622b953d7e36e19a0b9579b778925 Mon Sep 17 00:00:00 2001 From: Richard Sill Date: Wed, 4 Sep 2024 17:32:00 +0200 Subject: [PATCH 07/12] some more polish on various pages --- .../ROOT/pages/security/authorization.adoc | 6 ++++++ .../impersonation-and-user-switching.adoc | 2 +- modules/ROOT/pages/security/operations.adoc | 21 ++++++++++--------- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/modules/ROOT/pages/security/authorization.adoc b/modules/ROOT/pages/security/authorization.adoc index adb5aa1b..7c641f55 100644 --- a/modules/ROOT/pages/security/authorization.adoc +++ b/modules/ROOT/pages/security/authorization.adoc @@ -66,6 +66,9 @@ type Post @authorization(filter: [ } ---- +[NOTE] +If there is no `operations` argument with a list of operations, the GraphQL Library treats the authorization configuration as if the full list of operations had been provided. + === Validating @@ -115,6 +118,9 @@ type Post @authorization(validate: [ } ---- +[NOTE] +If there is no `operations` argument with a list of operations, the GraphQL Library treats the authorization configuration as if the full list of operations had been provided. + == Authorization without authentication diff --git a/modules/ROOT/pages/security/impersonation-and-user-switching.adoc b/modules/ROOT/pages/security/impersonation-and-user-switching.adoc index 34ec4863..7d0585e5 100644 --- a/modules/ROOT/pages/security/impersonation-and-user-switching.adoc +++ b/modules/ROOT/pages/security/impersonation-and-user-switching.adoc @@ -10,7 +10,7 @@ Impersonation still authenticates with the database as the original configured u 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). Consider the following an example of how to impersonate a different user per request. -Here the user to impersonate is taken from a HTTP header `User`: +Here the user to impersonate is taken from an HTTP header `User`: [.tabbed-example] ==== diff --git a/modules/ROOT/pages/security/operations.adoc b/modules/ROOT/pages/security/operations.adoc index 70ffa941..ebe848f5 100644 --- a/modules/ROOT/pages/security/operations.adoc +++ b/modules/ROOT/pages/security/operations.adoc @@ -2,9 +2,9 @@ //:page-aliases: /authentication-and-authorization/reference/operations.adoc, /security/reference/operations.adoc :description: This page describes how to set up authorization operations in the Neo4j GraphQL Library. -This reference runs through a number of worked GraphQL queries and how each location in each query triggers the evaluation of different authentication/authorization rules. +This page showcases a number of GraphQL queries and how you can trigger the evaluation of different authentication and authorization rules. -Each relevant location has a comment such as `CREATE ON OBJECT Movie`, which means an authentication directive such as the following would be evaluated: +Each relevant line has a comment such as `CREATE ON OBJECT Movie`, which means an authentication directive like the following is be evaluated: [source, graphql, indent=0] ---- @@ -14,7 +14,8 @@ type Movie @authentication(operations: [CREATE]) { } ---- -This also applies if the directive had no arguments, because `operations` defaults to _all_ operations. +[NOTE] +This also applies if the directive has no arguments because `operations` defaults to _all_ operations. The following examples apply to the `@authentication` directive, and also any rules within an `@authorization` directive. @@ -22,7 +23,7 @@ The following examples apply to the `@authentication` directive, and also any ru === Query -For a simple query, rules with `READ` in the operations will be evaluated for any type being read: +For a simple query, rules with `READ` in the operations are evaluated for any type being read: [source, graphql, indent=0] ---- @@ -38,7 +39,7 @@ query { === Mutation -For create Mutations, `CREATE` rules on the object will be evaluated for each node created, as well as field definition rules: +For `create` mutations, `CREATE` rules on the object are evaluated for each node created, as well as field definition rules: [source, graphql, indent=0] ---- @@ -55,7 +56,7 @@ mutation { } ---- -For single delete Mutations, rules with `DELETE` on the object will be evaluated: +For single `delete` mutations, rules with `DELETE` on the object are evaluated: [source, graphql, indent=0] ---- @@ -66,7 +67,7 @@ mutation { } ---- -For delete Mutations with nested delete operations, rules with operation `DELETE` will be evaluated: +For `delete` mutations with nested delete operations, rules with operation `DELETE` are evaluated: [source, graphql, indent=0] ---- @@ -80,7 +81,7 @@ mutation { } ---- -For a complex update Mutation with many effects, a variety of rules will be evaluated, as well as `READ` rules for the selection set: +For a complex `update` mutation with many effects, a variety of rules is evaluated, as well as `READ` rules for the selection set: [source, graphql, indent=0] ---- @@ -104,7 +105,7 @@ mutation { === Subscription -For a simple Subscription to creation events, both `SUBSCRIBE` and `READ` operations trigger rules: +For a simple subscription to creation events, both `SUBSCRIBE` and `READ` operations trigger rules: [source, graphql, indent=0] ---- @@ -117,7 +118,7 @@ subscription { } ---- -For a more complex Subscription to relationship events, both `SUBSCRIBE` is an operation, as well as `READ` to all relevant types: +For a more complex subscription to relationship events, `SUBSCRIBE` is an operation as well as `READ` to all relevant types: [source, graphql, indent=0] ---- From 4c283fc63c1f1f9f602f00ccf9dd28bd42c34c65 Mon Sep 17 00:00:00 2001 From: Richard Sill Date: Thu, 5 Sep 2024 09:42:41 +0200 Subject: [PATCH 08/12] rephrased index page a bit --- modules/ROOT/pages/security/index.adoc | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/modules/ROOT/pages/security/index.adoc b/modules/ROOT/pages/security/index.adoc index f5f81197..f35e0b19 100644 --- a/modules/ROOT/pages/security/index.adoc +++ b/modules/ROOT/pages/security/index.adoc @@ -5,10 +5,12 @@ auth/authorization.adoc, auth/auth-directive.adoc, auth/subscriptions.adoc, \ auth/authorization/allow.adoc, auth/authorization/bind.adoc, auth/authorization/roles.adoc, \ auth/authorization/where.adoc, authentication-and-authorization/index.adoc +The Neo4j GraphQL Library offers the following security features: -* xref::/security/configuration.adoc[Configuration] - Instructions to set up instantiation. -* xref::/security/authentication.adoc[Authentication] - Explicit authentication, configured using the `@authentication` directive. -* xref::/security/authorization.adoc[Authorization] - Authorization rules set using the `@authorization` directive. -* xref::/security/subscriptions-authorization.adoc[Subscriptions authorization] - Authorization rules for subscriptions set using the `@subscriptionsAuthorization` directive. -* xref::/security/impersonation-and-user-switching.adoc[Impersonation and user switching] - How to set up impersonation and user switching features. -* xref::/security/operations.adoc[Operations] - Reference on GraphQL queries and how each location in each query triggers the evaluation of different authentication/authorization rules. +* xref::/security/configuration.adoc[Configuration] of JSON Web Token (JWT) authentication with encoded or decoded JWTs. +* xref::/security/authentication.adoc[Authentication] for different operations on different parts of your schema with the `@authentication` directive. +* Rule-based xref::/security/authorization.adoc[authorization] filtering and validation with the `@authorization` directive. +* Rule-based xref::/security/subscriptions-authorization.adoc[subscriptions authorization] for subscriptions with the `@subscriptionsAuthorization` directive. +* xref::/security/impersonation-and-user-switching.adoc[User impersonation and switching]. + +See xref::/security/operations.adoc[Operations] for GraphQL query examples on how to trigger the evaluation of different authentication and authorization rules. From 127569c4ca00a4ee2e2b8b97943dd313e8e94b4d Mon Sep 17 00:00:00 2001 From: Richard Sill <156673635+rsill-neo4j@users.noreply.github.com> Date: Fri, 6 Sep 2024 09:22:27 +0200 Subject: [PATCH 09/12] Apply suggestions from code review Co-authored-by: Lidia Zuin <102308961+lidiazuin@users.noreply.github.com> --- .../ROOT/pages/security/authentication.adoc | 16 ++++++++------ .../ROOT/pages/security/authorization.adoc | 8 +++++-- .../ROOT/pages/security/configuration.adoc | 22 +++++++++++-------- modules/ROOT/pages/security/operations.adoc | 6 +++-- 4 files changed, 32 insertions(+), 20 deletions(-) diff --git a/modules/ROOT/pages/security/authentication.adoc b/modules/ROOT/pages/security/authentication.adoc index df10b84f..2d898ecd 100644 --- a/modules/ROOT/pages/security/authentication.adoc +++ b/modules/ROOT/pages/security/authentication.adoc @@ -3,8 +3,11 @@ The GraphQL Library offers the `@authentication` directive to configure authentication for certain operations and for different parts of your schema. -[NOTE] -Explicit authentication, configured with the `@authentication` directive, is only ever evaluated during Cypher translation time, and unauthenticated requests with queries requiring authentication never reach the database. +[IMPORTANT] +==== +Explicit authentication, configured with the `@authentication` directive, is only ever evaluated during Cypher translation time. +Unauthenticated requests with queries requiring authentication never reach the database. +==== == Operations @@ -19,7 +22,6 @@ Authentication can be configured to only be validated on certain operations: * `DELETE_RELATIONSHIP` * `SUBSCRIBE` - For instance, to only require authentication for the update or deletion of a user: [source, graphql, indent=0] @@ -32,15 +34,15 @@ type User @authentication(operations: [UPDATE, DELETE]) { ---- [NOTE] -If there is no `operations` argument with a list of operations, the GraphQL Library treats the authentication configuration as if the full list of operations had been provided. - +==== +In case there is no `operations` argument with a list of operations, the GraphQL Library treats the authentication configuration as if the full list of operations had been provided. +==== == Scope - === Global authentication -Athentication can be applied to the entire schema. +Authentication can be applied to the entire schema. This ensures authentication is checked for every matching request. Extend the schema: diff --git a/modules/ROOT/pages/security/authorization.adoc b/modules/ROOT/pages/security/authorization.adoc index 7c641f55..39a3f5f0 100644 --- a/modules/ROOT/pages/security/authorization.adoc +++ b/modules/ROOT/pages/security/authorization.adoc @@ -67,7 +67,9 @@ type Post @authorization(filter: [ ---- [NOTE] -If there is no `operations` argument with a list of operations, the GraphQL Library treats the authorization configuration as if the full list of operations had been provided. +==== +In case there is no `operations` argument with a list of operations, the GraphQL Library treats the authorization configuration as if the full list of operations had been provided. +==== === Validating @@ -119,7 +121,9 @@ type Post @authorization(validate: [ ---- [NOTE] -If there is no `operations` argument with a list of operations, the GraphQL Library treats the authorization configuration as if the full list of operations had been provided. +==== +In case there is no `operations` argument with a list of operations, the GraphQL Library treats the authorization configuration as if the full list of operations had been provided. +==== == Authorization without authentication diff --git a/modules/ROOT/pages/security/configuration.adoc b/modules/ROOT/pages/security/configuration.adoc index a256ce7e..2660cee1 100644 --- a/modules/ROOT/pages/security/configuration.adoc +++ b/modules/ROOT/pages/security/configuration.adoc @@ -5,7 +5,7 @@ The Neo4j GraphQL Library uses JSON Web Token (JWT) authentication. JWTs are tokens containing claims or statements about the user or client making the request. These claims can include information such as the user's ID or roles. -A JWT can be obtained from an authentication service and is then included in an API request. +A JWT can be obtained from an authentication service and then be included in an API request. The API verifies the JWT and returns the requested data if the JWT is valid. == Instantiation @@ -17,8 +17,9 @@ The Neo4j GraphQL Library can accept two types of JWTs: === Encoded JWTs -To use encoded JWTs, the library can be configured with a key to decode and verify the tokens. -The following code block uses Apollo Server, extracts the `Authorization` header from the request and puts it in the appropriate context field: +In order to use encoded JWTs, configure the library with a key to decode and verify the tokens. +The following code block uses Apollo Server. +It extracts the `Authorization` header from the request and puts it in the appropriate context field: [source, typescript, indent=0] ---- @@ -115,8 +116,9 @@ interface JwtPayload { ---- [WARNING] +==== Do not pass in the header or the signature. - +==== === Decoded JWTs @@ -136,8 +138,7 @@ const { url } = await startStandaloneServer(server, { ---- `customImplementation` is a placeholder for a function that provides a decoded JWT. -Using `jwt` instead of `token` in the `context` informs the Neo4jGraphQL library that it doesn't need to decode it. - +Using `jwt` instead of `token` in the `context` informs the Neo4j GraphQL Library that it doesn't need to decode it. == Adding JWT claims @@ -157,12 +158,15 @@ type JWT @jwt { ---- [NOTE] -Note that the type name `JWT` is not required. +==== +The type name `JWT` is not mandatory. You can use any name as long as it is decorated with the `@jwt` directive. +==== === The `@jwtClaim` directive -A `roles` claim is not necessarily located at the JWT payload root, but can instead be in a nested location, for example under `myApplication`: +A `roles` claim is not necessarily located at the JWT payload root. +It can instead be in a nested location, for example under `myApplication`: [source, json, indent=0] ---- @@ -195,7 +199,7 @@ Additionally, the nested location may contain `.` characters in the path, for ex } ---- -Escape these characters: +These characters must be escaped: [source, graphql, indent=0] ---- diff --git a/modules/ROOT/pages/security/operations.adoc b/modules/ROOT/pages/security/operations.adoc index ebe848f5..5c40095b 100644 --- a/modules/ROOT/pages/security/operations.adoc +++ b/modules/ROOT/pages/security/operations.adoc @@ -4,7 +4,7 @@ This page showcases a number of GraphQL queries and how you can trigger the evaluation of different authentication and authorization rules. -Each relevant line has a comment such as `CREATE ON OBJECT Movie`, which means an authentication directive like the following is be evaluated: +Each relevant line has a comment such as `CREATE ON OBJECT Movie`, which means an authentication directive like the following is evaluated: [source, graphql, indent=0] ---- @@ -14,8 +14,10 @@ type Movie @authentication(operations: [CREATE]) { } ---- -[NOTE] +[IMPORTANT] +==== This also applies if the directive has no arguments because `operations` defaults to _all_ operations. +==== The following examples apply to the `@authentication` directive, and also any rules within an `@authorization` directive. From c51c45848c957132a9fa033177545a485b1c124a Mon Sep 17 00:00:00 2001 From: Richard Sill Date: Fri, 6 Sep 2024 09:50:59 +0200 Subject: [PATCH 10/12] restored index page style --- modules/ROOT/pages/security/index.adoc | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/modules/ROOT/pages/security/index.adoc b/modules/ROOT/pages/security/index.adoc index f35e0b19..5ccc0cc8 100644 --- a/modules/ROOT/pages/security/index.adoc +++ b/modules/ROOT/pages/security/index.adoc @@ -5,12 +5,9 @@ auth/authorization.adoc, auth/auth-directive.adoc, auth/subscriptions.adoc, \ auth/authorization/allow.adoc, auth/authorization/bind.adoc, auth/authorization/roles.adoc, \ auth/authorization/where.adoc, authentication-and-authorization/index.adoc -The Neo4j GraphQL Library offers the following security features: - -* xref::/security/configuration.adoc[Configuration] of JSON Web Token (JWT) authentication with encoded or decoded JWTs. -* xref::/security/authentication.adoc[Authentication] for different operations on different parts of your schema with the `@authentication` directive. -* Rule-based xref::/security/authorization.adoc[authorization] filtering and validation with the `@authorization` directive. -* Rule-based xref::/security/subscriptions-authorization.adoc[subscriptions authorization] for subscriptions with the `@subscriptionsAuthorization` directive. -* xref::/security/impersonation-and-user-switching.adoc[User impersonation and switching]. - -See xref::/security/operations.adoc[Operations] for GraphQL query examples on how to trigger the evaluation of different authentication and authorization rules. +* xref::/security/configuration.adoc[Configuration] - Configuration of JSON Web Token (JWT) authentication with encoded or decoded JWTs. +* xref::/security/authentication.adoc[Authentication] - Explicit authentication for different operations on different parts of your schema with the `@authentication` directive. +* xref::/security/authorization.adoc[Authorization] - Rule-based authorization filtering and validation with the `@authorization` directive. +* xref::/security/subscriptions-authorization.adoc[Subscriptions authorization] - Rule-based authorization for subscriptions with the `@subscriptionsAuthorization` directive. +* xref::/security/impersonation-and-user-switching.adoc[Impersonation and user switching] - How to set up impersonation and user switching features. +* xref::/security/operations.adoc[Operations] - for GraphQL query examples on how to trigger the evaluation of different authentication and authorization rules. \ No newline at end of file From 12648b247064fd51288e1b0a0cc0aa90c4af64c9 Mon Sep 17 00:00:00 2001 From: Richard Sill Date: Fri, 6 Sep 2024 09:51:51 +0200 Subject: [PATCH 11/12] superfluous word --- modules/ROOT/pages/security/index.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ROOT/pages/security/index.adoc b/modules/ROOT/pages/security/index.adoc index 5ccc0cc8..9288e803 100644 --- a/modules/ROOT/pages/security/index.adoc +++ b/modules/ROOT/pages/security/index.adoc @@ -10,4 +10,4 @@ auth/authorization/where.adoc, authentication-and-authorization/index.adoc * xref::/security/authorization.adoc[Authorization] - Rule-based authorization filtering and validation with the `@authorization` directive. * xref::/security/subscriptions-authorization.adoc[Subscriptions authorization] - Rule-based authorization for subscriptions with the `@subscriptionsAuthorization` directive. * xref::/security/impersonation-and-user-switching.adoc[Impersonation and user switching] - How to set up impersonation and user switching features. -* xref::/security/operations.adoc[Operations] - for GraphQL query examples on how to trigger the evaluation of different authentication and authorization rules. \ No newline at end of file +* xref::/security/operations.adoc[Operations] - GraphQL query examples on how to trigger the evaluation of different authentication and authorization rules. \ No newline at end of file From 4a408beb4e02e7e29a55c7f21f8b80c19f2b969f Mon Sep 17 00:00:00 2001 From: Richard Sill <156673635+rsill-neo4j@users.noreply.github.com> Date: Tue, 17 Sep 2024 13:26:30 +0200 Subject: [PATCH 12/12] Apply suggestions from code review --- modules/ROOT/pages/security/authentication.adoc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/modules/ROOT/pages/security/authentication.adoc b/modules/ROOT/pages/security/authentication.adoc index 2d898ecd..b8a089a8 100644 --- a/modules/ROOT/pages/security/authentication.adoc +++ b/modules/ROOT/pages/security/authentication.adoc @@ -52,9 +52,12 @@ Extend the schema: extend schema @authentication ---- -The `operations` and `jwt` arguments can also be used when the directive is applied to a schema extension. +The `operations` and `jwt` arguments can also be used when the directive is applied to a schema extension, for example: -// ^ should we add links or provide examples? +[source, graphql, indent=0] +---- +extend schema @authentication(operations: [UPDATE, DELETE], jwt: { roles_INCLUDES: "admin" }) +---- === Authentication for types