Skip to content

Commit 187afba

Browse files
authored
Merge pull request #245 from neo4j/cherry-pick-auth-docs-to-6.x
cherry-pick authorization docs to 6.x
2 parents b929bc9 + ecd5a97 commit 187afba

File tree

6 files changed

+745
-884
lines changed

6 files changed

+745
-884
lines changed

modules/ROOT/pages/security/authentication.adoc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ Authentication can be configured for an entire type:
6565

6666
[source, graphql, indent=0]
6767
----
68-
type User @authentication {
68+
type User @authentication @node {
6969
id: ID!
7070
name: String!
7171
password: String!
@@ -89,7 +89,7 @@ Authentication can be configured on a per-field basis, for example:
8989

9090
[source, graphql, indent=0]
9191
----
92-
type User {
92+
type User @node {
9393
id: ID!
9494
name: String!
9595
password: String! @authentication

modules/ROOT/pages/security/authorization.adoc

Lines changed: 124 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ For instance, to only require filtering for the reading and aggregating posts:
5656
[source, graphql, indent=0]
5757
----
5858
type Post @node @authorization(filter: [
59-
{ operations: [READ, AGGREGATE] where: { node: { author: { id_EQ: "$jwt.sub" } } } }
59+
{ operations: [READ, AGGREGATE], where: { node: { author: { id_EQ: "$jwt.sub" } } } }
6060
]) {
6161
title: String!
6262
content: String!
@@ -106,11 +106,10 @@ Validation can be configured to only be performed on certain operations:
106106

107107
For instance, to only require validation for the update or deletion of a post:
108108

109-
110109
[source, graphql, indent=0]
111110
----
112111
type Post @node @authorization(validate: [
113-
{ operations: [UPDATE, DELETE] where: { node: { author: { id_EQ: "$jwt.sub" } } } }
112+
{ operations: [UPDATE, DELETE], where: { node: { author: { id_EQ: "$jwt.sub" } } } }
114113
]) {
115114
title: String!
116115
content: String!
@@ -123,6 +122,98 @@ type Post @node @authorization(validate: [
123122
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.
124123
====
125124

125+
=== When
126+
127+
Validation can be configured to only be performed before or after an operation is executed.
128+
This is done using the `when` argument which accepts an array of the following values:
129+
130+
* `BEFORE`
131+
* `AFTER`
132+
133+
Additionally, some operations only support validation either before or after them, which is summarised in this table:
134+
135+
[cols="2,5"]
136+
|===
137+
| `operation` | `when`
138+
139+
| `READ`
140+
| `BEFORE`
141+
142+
| `AGGREGATE`
143+
| `BEFORE`
144+
145+
| `CREATE`
146+
| `AFTER`
147+
148+
| `UPDATE`
149+
| `BEFORE`, `AFTER`
150+
151+
| `DELETE`
152+
| `BEFORE`
153+
154+
| `CREATE_RELATIONSHIP`
155+
| `BEFORE`, `AFTER`
156+
157+
| `DELETE_RELATIONSHIP`
158+
| `BEFORE`, `AFTER`
159+
160+
|===
161+
162+
As an example, let's say you want someone to be able to update a post.
163+
If you want to check that after the update the author of the post is still the current user, do the following:
164+
165+
[source, graphql, indent=0]
166+
----
167+
type Post @node @authorization(validate: [
168+
{ operations: [UPDATE], when: [AFTER], where: { node: { author: { id: "$jwt.sub" } } } }
169+
]) {
170+
title: String!
171+
content: String!
172+
author: User! @relationship(type: "AUTHORED", direction: IN)
173+
}
174+
----
175+
176+
== Authorization on fields
177+
178+
The `@authorization` directive can be used either on object types or their fields, with the former being used in examples for the most part on this page.
179+
When applied to a field, the authorization rules are only evaluated if the matching operations are performed on that field.
180+
For example, consider a `User` type with a `password` field:
181+
182+
[source, graphql, indent=0]
183+
----
184+
type User @node {
185+
id: ID!
186+
username: String!
187+
password: String! @authorization(where: [{ operations: [READ, UPDATE], where: { node: { id: "$jwt.sub" } } }])
188+
}
189+
----
190+
191+
When executing the following query, a valid identity is not needed:
192+
193+
[source, graphql, indent=0]
194+
----
195+
{
196+
users {
197+
username
198+
}
199+
}
200+
----
201+
202+
However, consider the following query:
203+
204+
[source, graphql, indent=0]
205+
----
206+
{
207+
users {
208+
username
209+
password
210+
}
211+
}
212+
----
213+
214+
This will require a valid JWT to have been provided with the request, and the matching users will be filtered down according to the JWT subject.
215+
The same applies for attempting to update the `password` field, the update will only apply to the user matching the JWT.
216+
126217

127218
== Authorization without authentication
128219

@@ -147,3 +238,33 @@ type Post @node @authorization(filter: [
147238
author: User! @relationship(type: "AUTHORED", direction: IN)
148239
}
149240
----
241+
242+
== Ordering of rules
243+
244+
In each ruleset (`filter` and `validate`), rules are joined with an `OR`.
245+
The two rulesets are joined with an `AND`.
246+
247+
For example, the following would allow for the update of a `User` node if the JWT roles claim includes `admin` _or_ if the `locked` property on the node is `false`:
248+
249+
[source, graphql, indent=0]
250+
----
251+
type User @node @authorization(validate: [
252+
{ operations: [UPDATE], where: { jwt: { roles_INCLUDES: "admin" } } }
253+
{ operations: [UPDATE], where: { node: { locked: false } } }
254+
]) {
255+
id: ID!
256+
locked: Boolean!
257+
}
258+
----
259+
260+
If you want to combine the rule that a user must be an admin with the rule that the `locked` property must be `false` in order to update a `User` node, add them both to the `where` field using `AND` in a single rule:
261+
262+
[source, graphql, indent=0]
263+
----
264+
type User @node @authorization(validate: [
265+
{ operations: [UPDATE], where: { AND: [{ jwt: { roles_INCLUDES: "admin" } }, { node: { locked: false } }] } }
266+
]) {
267+
id: ID!
268+
locked: Boolean!
269+
}
270+
----

modules/ROOT/pages/security/operations.adoc

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,70 @@ query {
3737
}
3838
----
3939

40+
=== Connection
41+
42+
For a connection query, rules with `READ` in the operations are evaluated for any type being read:
43+
44+
[source, graphql, indent=0]
45+
----
46+
query {
47+
moviesConnection {
48+
edges {
49+
node { # READ ON OBJECT Movie
50+
title # READ ON FIELD_DEFINITION Movie.title
51+
actorsConnection {
52+
edges {
53+
node { # READ ON OBJECT Actor
54+
name # READ ON FIELD_DEFINITION Actor.name
55+
}
56+
}
57+
}
58+
}
59+
}
60+
}
61+
}
62+
----
63+
64+
=== Aggregation
65+
66+
For an aggregation query, rules with `AGGREGATE` in the operations are evaluated for any type being aggregated:
67+
68+
[source, graphql, indent=0]
69+
----
70+
query {
71+
moviesConnection {
72+
aggregate { # AGGREGATE ON OBJECT Movie
73+
title { # AGGREGATE ON FIELD_DEFINITION Movie.title
74+
longest
75+
}
76+
}
77+
}
78+
}
79+
----
80+
81+
The same logic applies to aggregations of nested nodes:
82+
83+
[source, graphql, indent=0]
84+
----
85+
query {
86+
movies {
87+
actorsConnection {
88+
aggregate { # AGGREGATE ON OBJECT Actor
89+
node {
90+
name { # AGGREGATE ON FIELD_DEFINITION Actor.name
91+
longest
92+
}
93+
}
94+
}
95+
}
96+
}
97+
}
98+
----
99+
40100
== Mutation
41101

102+
=== Create
103+
42104
For `create` mutations, `CREATE` rules on the object are evaluated for each node created, as well as field definition rules:
43105

44106
[source, graphql, indent=0]
@@ -56,6 +118,8 @@ mutation {
56118
}
57119
----
58120

121+
=== Delete
122+
59123
For single `delete` mutations, rules with `DELETE` on the object are evaluated:
60124

61125
[source, graphql, indent=0]
@@ -81,6 +145,8 @@ mutation {
81145
}
82146
----
83147

148+
=== Update
149+
84150
For a complex `update` mutation with many effects, a variety of rules is evaluated, as well as `READ` rules for the selection set:
85151

86152
[source, graphql, indent=0]

modules/ROOT/pages/security/subscriptions-authorization.adoc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
= Subscriptions authorization
44

55
Subscriptions require their own authorization rules, which are configured with the `@subscriptionsAuthorization` directive.
6-
These rules are different to authorization rules for queries and mutations because they use filtering rules available for subscriptions events.
6+
These rules are different to authorization rules for queries and mutations because they use filtering rules available for subscriptions events.
7+
These filtering rules can only be used to filter against the properties of the nodes impacted by the events.
78

89
All subscriptions authorization rules have an implied requirement for authentication, given that the rules are normally evaluated against values in the JWT payload.
910

modules/ROOT/pages/types/relationships.adoc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ You can add relationship properties to the example in two steps:
6565
. Add a type definition decorated with the `@relationshipProperties` directive, containing the desired relationship properties.
6666
. Add a `properties` argument to both "sides" (or just one side, if you prefer) of the `@relationship` directive which points to the newly defined interface.
6767

68+
Relationship properties fields can only be primitive types or their list variants.
69+
You cannot map complex types such as object types into the types modelling relationship properties.
70+
6871
For example, suppose you want to distinguish which roles an actor played in a movie:
6972

7073
[source, graphql, indent=0]

0 commit comments

Comments
 (0)