Commit 89fa5cd
authored
feat(router): support authenticated and requiresScopes directives (#538)
The implementation is based on the analysis from issue #351.
The authorization logic can be configured to operate in two modes:
- **`filter` (default mode):** This mode silently removes any fields
from the incoming GraphQL operation that the user is not authorized to
access. For each field removed, a corresponding `AuthorizationError` is
added to the `errors` array in the GraphQL response, while the rest of
the accessible data is returned as requested.
- **`reject` mode:** In this mode, the router will reject any GraphQL
operation that attempts to access one or more unauthorized fields. The
entire request is denied, and a descriptive error is returned.
Access control is defined within the supergraph schema using the
following directives:
- `@authenticated`: Restricts access to a field to only authenticated
users.
- `@requiresScopes(scopes: [[String]])`: Provides more granular control
by requiring the user to possess specific scopes. The directive supports
`AND` logic for scopes within a nested list (e.g., `["read:users",
"write:users"]`) and `OR` logic for scopes across nested lists (e.g.,
`[["read:users"], ["admin:users"]]`).
## Key Implementation Details
- **Three-Phase Process:** The authorization logic is designed for high
performance and is executed in three phases:
1. **Build Authorization Metadata:** when router loads the supergraph,
it parses also the supergraph schema to create an in-memory
representation of all `@authenticated` and `@requiresScopes` directives.
This metadata is built once and reused for all incoming requests.
2. **Collect Unauthorized Paths:** For each incoming operation, the
authorization logic traverses the query. It checks each field against
the pre-built metadata and the current `UserAuthContext`. An
`UnauthorizedPathTree` data structure is used to efficiently collect all
field paths that the user is not permitted to access.
3. **Transform or Reject the Operation:** Based on the findings from the
previous phase and the configured mode, a final decision is made. In
`filter` mode, if any unauthorized paths were found, the original
operation is rebuilt, stripping out only the unauthorized fields to
create a new, sanitized operation. In `reject` mode, the presence of any
unauthorized path leads to an rejection of the entire request.
- **Performance-First Design:** Authorization is a critical path in the
request pipeline, this feature was developed with efficiency as a core
principle. A new suite of benchmarks has been added to measure its
performance impact. The results are good, demonstrating that the entire
authorization process adds a negligible overhead of just **1-4
microseconds** for medium-sized queries, ensuring that security does not
come at the cost of performance.
- **Pre-Query Planning Execution:** Authorization is performed on the
operation's Abstract Syntax Tree (AST) before the query planning and
execution stages. This ensures that unauthorized field requests never
reach the subgraphs, preventing potential data leaks and unnecessary
processing.
- **Decoupled from Authentication:** The core logic operates on a
`UserAuthContext` struct, which contains the user's authentication
status and a set of scopes. This decouples the authorization mechanism
from the specific authentication method (e.g., JWT validation).
- **Comprehensive GraphQL Support:** The implementation correctly
handles various GraphQL features to ensure authorization is applied
accurately, including:
- Conditional directives (`@include` and `@skip`), where authorization
is bypassed for fields that are not included in the final operation.
- Complex inheritance scenarios with interfaces and object types,
correctly applying authorization rules defined on both.
- **Test Coverage:** Suite of end-to-end tests for both `filter` and
`reject` modes, covering various scenarios.1 parent 5dab3d3 commit 89fa5cd
File tree
46 files changed
+8479
-122
lines changed- .changeset
- bench
- subgraphs
- bin/router
- benches
- src
- pipeline
- authorization
- docs
- e2e
- configs
- src
- lib
- executor/src
- execution
- introspection
- projection
- variables
- query-planner/src
- ast
- consumer_schema
- federation_spec
- planner
- state
- router-config/src
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
46 files changed
+8479
-122
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
| 1 | + | |
| 2 | + | |
| 3 | + | |
2 | 4 | | |
3 | 5 | | |
4 | 6 | | |
| |||
42 | 44 | | |
43 | 45 | | |
44 | 46 | | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
45 | 72 | | |
| 73 | + | |
46 | 74 | | |
47 | 75 | | |
48 | 76 | | |
49 | 77 | | |
50 | 78 | | |
51 | 79 | | |
52 | 80 | | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
53 | 112 | | |
54 | 113 | | |
55 | 114 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
| 11 | + | |
| 12 | + | |
11 | 13 | | |
12 | 14 | | |
13 | 15 | | |
14 | 16 | | |
15 | 17 | | |
16 | 18 | | |
| 19 | + | |
| 20 | + | |
17 | 21 | | |
18 | 22 | | |
19 | 23 | | |
20 | 24 | | |
21 | 25 | | |
22 | 26 | | |
| 27 | + | |
| 28 | + | |
23 | 29 | | |
24 | 30 | | |
25 | 31 | | |
26 | 32 | | |
27 | 33 | | |
28 | 34 | | |
| 35 | + | |
| 36 | + | |
29 | 37 | | |
30 | 38 | | |
31 | 39 | | |
32 | 40 | | |
33 | 41 | | |
34 | 42 | | |
| 43 | + | |
| 44 | + | |
35 | 45 | | |
36 | 46 | | |
37 | 47 | | |
38 | 48 | | |
39 | 49 | | |
40 | 50 | | |
| 51 | + | |
| 52 | + | |
41 | 53 | | |
42 | 54 | | |
43 | 55 | | |
44 | 56 | | |
45 | 57 | | |
46 | 58 | | |
| 59 | + | |
| 60 | + | |
47 | 61 | | |
48 | 62 | | |
49 | 63 | | |
50 | 64 | | |
51 | 65 | | |
52 | 66 | | |
| 67 | + | |
| 68 | + | |
53 | 69 | | |
54 | 70 | | |
55 | 71 | | |
56 | 72 | | |
57 | 73 | | |
58 | 74 | | |
| 75 | + | |
| 76 | + | |
59 | 77 | | |
60 | 78 | | |
61 | 79 | | |
| |||
65 | 83 | | |
66 | 84 | | |
67 | 85 | | |
| 86 | + | |
| 87 | + | |
68 | 88 | | |
69 | 89 | | |
70 | 90 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
82 | 82 | | |
83 | 83 | | |
84 | 84 | | |
| 85 | + | |
| 86 | + | |
85 | 87 | | |
86 | 88 | | |
87 | 89 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
54 | 54 | | |
55 | 55 | | |
56 | 56 | | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
0 commit comments