composition updates related to merging auth directives (backport)#3326
Merged
dariuszkuc merged 5 commits intoversion-2.10from Nov 4, 2025
Merged
composition updates related to merging auth directives (backport)#3326dariuszkuc merged 5 commits intoversion-2.10from
dariuszkuc merged 5 commits intoversion-2.10from
Conversation
Restricts usage of `@authenticated`, `@policy` and `@requiresScopes` from being applied on interfaces, interface objects and their fields. GraphQL spec currently does not define any interface inheritance rules and developers have to explicitly redefine all interface fields on their implementations. At runtime, GraphQL servers cannot return abstract types and always return concrete output types. Due to the above, applying auth directives on the interfaces may lead to unexpected runtime behavior as they won't have any effect at runtime.
Adds new `postMergeValidation` check to ensure that all fields that depends on data from other parts of the supergraph through `@requires` and/or `@fromContext` directives explicitly specify matching `@authenticated`, `@requiresScopes` and/or `@policy` auth requirements, e.g. ```graphql type T @key(fields: "id") { id: ID! extra: String @external # we need explicit @authenticated as it is needed to access extra requiresExtra: String @requires(fields: "extra") @authenticated } type T @key(fields: "id") { id: ID! extra: String @authenticated } ```
Current merge policies for `@authenticated`, `@requiresScopes` and `@policy` were inconsistent. If single subgraph declared a field with one of the directives then it would restrict access to this supergraph field regardless which subgraph would resolve this field (results in `AND` rule for any applied auth directive, i.e. `@authenticated` AND `@policy` is required to access this field). If the same auth directive (`@requiresScopes`/`@policy`) were applied across the subgraphs then the resulting supergraph field could be resolved by fullfilling either one of the subgraph requirements (resulting in `OR` rule, i.e. either `@policy` 1 or `@policy` 2 has to be true to access the field). While arguably this allowed for easier schema evolution, it did result in weakening the security requirements. Since `@policy` and `@requiresScopes` values are represent boolean conditions in Disjunctive Normal Form, we can merge them conjunctively to get the final auth requirements, i.e. ```graphql type T @authenticated { # requires scopes (A1 AND A2) OR A3 secret: String @requiresScopes(scopes: [["A1", "A2"], ["A3"]]) } type T { # requires scopes B1 OR B2 secret: String @requiresScopes(scopes: [["B1"], ["B2"]] } type T @authenticated { secret: String @requiresScopes( scopes: [ ["A1", "A2", "B1"], ["A1", "A2", "B2"], ["A3", "B1"], ["A3", "B2"] ]) } ``` This algorithm also deduplicates redundant requirements, e.g. ```graphql type T { # requires A1 AND A2 scopes to access secret: String @requiresScopes(scopes: [["A1", "A2"]]) } type T { # requires only A1 scope to access secret: String @requiresScopes(scopes: [["A1"]]) } type T { # requires only A1 scope to access as A2 is redundant secret: String @requiresScopes(scopes: [["A1"]]) } ```
… in supergraph Propagate auth requirements from polymorphic types upwards to their interfaces. This ensures consistent router runtime behavior regardless of the router version.
🦋 Changeset detectedLatest commit: b3ec52e The changes in this PR will be included in the next version bump. This PR includes changesets to release 7 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
✅ Docs preview readyThe preview is ready to be viewed. View the preview File Changes 0 new, 7 changed, 10 removedBuild ID: 7dd97a33eb6399fee208f72a URL: https://www.apollographql.com/docs/deploy-preview/7dd97a33eb6399fee208f72a |
|
This pull request is automatically built and testable in CodeSandbox. To see build info of the built libraries, click here or the icon next to each commit SHA. |
dariuszkuc
pushed a commit
that referenced
this pull request
Nov 4, 2025
This PR was opened by the [Changesets release](https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to version-2.10, this PR will be updated. # Releases ## @apollo/composition@2.10.3 ### Patch Changes - Automatically propagate authorization requirements from implementing type to interface in the supergraph. ([#3326](#3326)) Authorization requirements now automatically propagate from implementing types to interfaces during composition. Direct auth specifications on interfaces are no longer allowed. Interface access requires satisfying ALL implementing types' requirements (`AND` rule), with these requirements included in the supergraph for backward compatibility with older routers. - Fix transitive auth requirements on `@requires` and `@fromcontext` ([#3326](#3326)) Adds new `postMergeValidation` check to ensure that all fields that depends on data from other parts of the supergraph through `@requires` and/or `@fromContext` directives explicitly specify matching `@authenticated`, `@requiresScopes` and/or `@policy` auth requirements, e.g. ```graphql type T @key(fields: "id") { id: ID! extra: String @external # we need explicit `@authenticated` as it is needed to access extra requiresExtra: String @requires(fields: "extra") @authenticated } type T @key(fields: "id") { id: ID! extra: String @authenticated } ``` - Restrict usage of auth directives on interfaces ([#3326](#3326)) Restricts usage of `@authenticated`, `@policy` and `@requiresScopes` from being applied on interfaces, interface objects and their fields. GraphQL spec currently does not define any interface inheritance rules and developers have to explicitly redefine all interface fields on their implementations. At runtime, GraphQL servers cannot return abstract types and always return concrete output types. Due to the above, applying auth directives on the interfaces may lead to unexpected runtime behavior as they won't have any effect at runtime. - Stricter merge rules for @requiresScopes and @Policy ([#3326](#3326)) Current merge policies for `@authenticated`, `@requiresScopes` and `@policy` were inconsistent. If a shared field uses the same authorization directives across subgraphs, composition merges them using `OR` logic. However, if a shared field uses different authorization directives across subgraphs composition merges them using `AND` logic. This simplified schema evolution, but weakened security requirements. Therefore, the behavior has been changed to always apply `AND` logic to authorization directives applied to the same field across subgraphs. Since `@policy` and `@requiresScopes` values represent boolean conditions in Disjunctive Normal Form, we can merge them conjunctively to get the final auth requirements. For example: ```graphql # subgraph A type T @authenticated { # requires scopes (A1 AND A2) OR A3 secret: String @requiresScopes(scopes: [["A1", "A2"], ["A3"]]) } # subgraph B type T { # requires scopes B1 OR B2 secret: String @requiresScopes(scopes: [["B1"], ["B2"]] } # composed supergraph type T @authenticated { secret: String @requiresScopes( scopes: [ ["A1", "A2", "B1"], ["A1", "A2", "B2"], ["A3", "B1"], ["A3", "B2"] ]) } ``` This algorithm also deduplicates redundant requirements, e.g. ```graphql # subgraph A type T { # requires A1 AND A2 scopes to access secret: String @requiresScopes(scopes: [["A1", "A2"]]) } # subgraph B type T { # requires only A1 scope to access secret: String @requiresScopes(scopes: [["A1"]]) } # composed supergraph type T { # requires only A1 scope to access as A2 is redundant secret: String @requiresScopes(scopes: [["A1"]]) } ``` - Updated dependencies \[[`2b88aec38d5bacb6ec815d885fdac47ef415124a`](2b88aec), [`18a9cfaf533602bb37fdf22962539ce0eae948c8`](18a9cfa), [`9c0aaa0874c98ae8ce0cc38cad7f6f25d2c29635`](9c0aaa0), [`f94e7b35c43ed64c67ff25c7aeb86ec0dd73370a`](f94e7b3)]: - @apollo/federation-internals@2.10.3 - @apollo/query-graphs@2.10.3 ## @apollo/gateway@2.10.3 ### Patch Changes - Updated dependencies \[[`2b88aec38d5bacb6ec815d885fdac47ef415124a`](2b88aec), [`18a9cfaf533602bb37fdf22962539ce0eae948c8`](18a9cfa), [`9c0aaa0874c98ae8ce0cc38cad7f6f25d2c29635`](9c0aaa0), [`f94e7b35c43ed64c67ff25c7aeb86ec0dd73370a`](f94e7b3)]: - @apollo/composition@2.10.3 - @apollo/federation-internals@2.10.3 - @apollo/query-planner@2.10.3 ## @apollo/federation-internals@2.10.3 ### Patch Changes - Automatically propagate authorization requirements from implementing type to interface in the supergraph. ([#3326](#3326)) Authorization requirements now automatically propagate from implementing types to interfaces during composition. Direct auth specifications on interfaces are no longer allowed. Interface access requires satisfying ALL implementing types' requirements (`AND` rule), with these requirements included in the supergraph for backward compatibility with older routers. - Fix transitive auth requirements on `@requires` and `@fromcontext` ([#3326](#3326)) Adds new `postMergeValidation` check to ensure that all fields that depends on data from other parts of the supergraph through `@requires` and/or `@fromContext` directives explicitly specify matching `@authenticated`, `@requiresScopes` and/or `@policy` auth requirements, e.g. ```graphql type T @key(fields: "id") { id: ID! extra: String @external # we need explicit `@authenticated` as it is needed to access extra requiresExtra: String @requires(fields: "extra") @authenticated } type T @key(fields: "id") { id: ID! extra: String @authenticated } ``` - Restrict usage of auth directives on interfaces ([#3326](#3326)) Restricts usage of `@authenticated`, `@policy` and `@requiresScopes` from being applied on interfaces, interface objects and their fields. GraphQL spec currently does not define any interface inheritance rules and developers have to explicitly redefine all interface fields on their implementations. At runtime, GraphQL servers cannot return abstract types and always return concrete output types. Due to the above, applying auth directives on the interfaces may lead to unexpected runtime behavior as they won't have any effect at runtime. - Stricter merge rules for @requiresScopes and @Policy ([#3326](#3326)) Current merge policies for `@authenticated`, `@requiresScopes` and `@policy` were inconsistent. If a shared field uses the same authorization directives across subgraphs, composition merges them using `OR` logic. However, if a shared field uses different authorization directives across subgraphs composition merges them using `AND` logic. This simplified schema evolution, but weakened security requirements. Therefore, the behavior has been changed to always apply `AND` logic to authorization directives applied to the same field across subgraphs. Since `@policy` and `@requiresScopes` values represent boolean conditions in Disjunctive Normal Form, we can merge them conjunctively to get the final auth requirements. For example: ```graphql # subgraph A type T @authenticated { # requires scopes (A1 AND A2) OR A3 secret: String @requiresScopes(scopes: [["A1", "A2"], ["A3"]]) } # subgraph B type T { # requires scopes B1 OR B2 secret: String @requiresScopes(scopes: [["B1"], ["B2"]] } # composed supergraph type T @authenticated { secret: String @requiresScopes( scopes: [ ["A1", "A2", "B1"], ["A1", "A2", "B2"], ["A3", "B1"], ["A3", "B2"] ]) } ``` This algorithm also deduplicates redundant requirements, e.g. ```graphql # subgraph A type T { # requires A1 AND A2 scopes to access secret: String @requiresScopes(scopes: [["A1", "A2"]]) } # subgraph B type T { # requires only A1 scope to access secret: String @requiresScopes(scopes: [["A1"]]) } # composed supergraph type T { # requires only A1 scope to access as A2 is redundant secret: String @requiresScopes(scopes: [["A1"]]) } ``` ## @apollo/query-graphs@2.10.3 ### Patch Changes - Updated dependencies \[[`2b88aec38d5bacb6ec815d885fdac47ef415124a`](2b88aec), [`18a9cfaf533602bb37fdf22962539ce0eae948c8`](18a9cfa), [`9c0aaa0874c98ae8ce0cc38cad7f6f25d2c29635`](9c0aaa0), [`f94e7b35c43ed64c67ff25c7aeb86ec0dd73370a`](f94e7b3)]: - @apollo/federation-internals@2.10.3 ## @apollo/query-planner@2.10.3 ### Patch Changes - Updated dependencies \[[`2b88aec38d5bacb6ec815d885fdac47ef415124a`](2b88aec), [`18a9cfaf533602bb37fdf22962539ce0eae948c8`](18a9cfa), [`9c0aaa0874c98ae8ce0cc38cad7f6f25d2c29635`](9c0aaa0), [`f94e7b35c43ed64c67ff25c7aeb86ec0dd73370a`](f94e7b3)]: - @apollo/federation-internals@2.10.3 - @apollo/query-graphs@2.10.3 ## @apollo/subgraph@2.10.3 ### Patch Changes - Updated dependencies \[[`2b88aec38d5bacb6ec815d885fdac47ef415124a`](2b88aec), [`18a9cfaf533602bb37fdf22962539ce0eae948c8`](18a9cfa), [`9c0aaa0874c98ae8ce0cc38cad7f6f25d2c29635`](9c0aaa0), [`f94e7b35c43ed64c67ff25c7aeb86ec0dd73370a`](f94e7b3)]: - @apollo/federation-internals@2.10.3 ## apollo-federation-integration-testsuite@2.10.3 Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Composition updates:
@requiresand@fromContext@requiresScopesand@policy(change fromORtoANDlogic)Backport of #3321