Skip to content

Commit 3e20033

Browse files
committed
Add missing authorization documentation
1 parent 5a09ede commit 3e20033

File tree

1 file changed

+121
-3
lines changed

1 file changed

+121
-3
lines changed

modules/ROOT/pages/security/authorization.adoc

Lines changed: 121 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 @authorization(filter: [
59-
{ operations: [READ, AGGREGATE] where: { node: { author: { id: "$jwt.sub" } } } }
59+
{ operations: [READ, AGGREGATE], where: { node: { author: { id: "$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 @authorization(validate: [
113-
{ operations: [UPDATE, DELETE] where: { node: { author: { id: "$jwt.sub" } } } }
112+
{ operations: [UPDATE, DELETE], where: { node: { author: { id: "$jwt.sub" } } } }
114113
]) {
115114
title: String!
116115
content: String!
@@ -123,6 +122,94 @@ type Post @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 a brief example, if you wanted anybody to be able to attempt to update any post, but wanted to check that after the update, the author it is connected to is still the current user, you could do the following:
163+
164+
[source, graphql, indent=0]
165+
----
166+
type Post @authorization(validate: [
167+
{ operations: [UPDATE], when: [AFTER], where: { node: { author: { id: "$jwt.sub" } } } }
168+
]) {
169+
title: String!
170+
content: String!
171+
author: User! @relationship(type: "AUTHORED", direction: IN)
172+
}
173+
----
174+
175+
== Authorization on fields
176+
177+
The `@authorization` directive can be used either on either object types or their fields, with the former being used in examples for the most part on this page. When applied to a field, the authorization rules are only evaluated if the matching operations are performed on that field. For example, consider a `User` type with a `password` field:
178+
179+
[source, graphql, indent=0]
180+
----
181+
type User {
182+
id: ID!
183+
username: String!
184+
password: String! @authorization(where: [{ operations: [READ, UPDATE], where: { node: { id: "$jwt.sub" } } }])
185+
}
186+
----
187+
188+
When executing the following query, a valid identity is not needed:
189+
190+
[source, graphql, indent=0]
191+
----
192+
{
193+
users {
194+
username
195+
}
196+
}
197+
----
198+
199+
However, consider the following query:
200+
201+
[source, graphql, indent=0]
202+
----
203+
{
204+
users {
205+
username
206+
password
207+
}
208+
}
209+
----
210+
211+
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. The same will apply for attempting to update the `password` field, the update will only apply to the user matching the JWT.
212+
126213

127214
== Authorization without authentication
128215

@@ -147,3 +234,34 @@ type Post @authorization(filter: [
147234
author: User! @relationship(type: "AUTHORED", direction: IN)
148235
}
149236
----
237+
238+
== Ordering of rules
239+
240+
In each ruleset (`filter` and `validate`), rules are joined with an `OR`. The two rulesets are joined with an `AND`.
241+
242+
An example pseudo-logic would be `(filterRule1 OR filterRule2) AND (validateRule1 OR validateRule2)`.
243+
244+
If ever there are two rules which you would like to be combined with an `AND`, these should be combined into a single rule. Take for instance the following example:
245+
246+
[source, graphql, indent=0]
247+
----
248+
type User @authorization(validate: [
249+
{ operations: [UPDATE], where: { jwt: { roles_INCLUDES: "admin" } } }
250+
{ operations: [UPDATE], where: { node: { locked: false } } }
251+
]) {
252+
id: ID!
253+
locked: Boolean!
254+
}
255+
----
256+
257+
Say in this example we wanted it to be that a user needs to be an admin _and_ the `locked` property must be `false` in order to update a `User` node. We would need to combine these predicates into a single rule:
258+
259+
[source, graphql, indent=0]
260+
----
261+
type User @authorization(validate: [
262+
{ operations: [UPDATE], where: { AND: [{ jwt: { roles_INCLUDES: "admin" } }, { node: { locked: false } }] } }
263+
]) {
264+
id: ID!
265+
locked: Boolean!
266+
}
267+
----

0 commit comments

Comments
 (0)