Minimum requirements
Make sure you have correctly set up Authentication & Authorization.
Definition
Arguments
The “scopes” argument requires an array (GraphQL List) of nested arrays.
The outer array represents a set of OR scopes—the token must satisfy at least one of the inner arrays.
Each inner array represents a set of AND scopes—the token must possess all scopes within that array.
In other words,
scopes: [["a", "b"], ["c"]] means: ("a" AND "b") OR ("c").
Each element in the AND scopes array should be an openfed__Scope Scalar, which is an instance of permissions as
defined in your authentication token.
For example, "read:field".
Declaration
OR Scopes
Consider the following@requiresScopes declared on Query.a:
Query.a, it would require EITHER the "read:field" permission OR the "read:scalar"
permission.
AND Scopes
Consider the following @requiresScopes declared onQuery.b:
Query.b, it would require BOTH the "read:field" permission and the "read:scalar"
permission.
Lack of one or both would return an authorization error.
Multiple OR scopes with multiple AND scopes
Consider the following@requiresScopes declared on Query.c:
Query.c, it would require at least one of the following sets of scopes:
(("read:field" AND "read:scalar") OR ("read:query" AND "read:private") OR ("read:all"))
Declaration
The@requiresScopes directive can be declared on Enums, field definitions, Interfaces, Objects, and Scalars.
Declaration on field definitions (Interface and Object fields)
When@requiresScopes is declared on an Object field definition, that specific field will be protected (require
the specified scopes).
For example, given the following federated schema:
Query.ids would be protected in the following operation:
Interface.id would be protected in the following operation
(but note that @requiresScopes declared on an Interface field does not protect the fields of its implementations):
Declaration on the “type level” (Enums, Interfaces, Objects, and Scalars)
When@requiresScopes is declared on the “type level”, all field definitions with that named type (the innermost
response type name) will require those scopes to access.
For example, consider the following federated schema:
@requiresScopes has been declared on:
- The Enum “Enum”
- The Interface “Interface”
- The Object “ObjectB”
- The Scalar “Scalar”
Query.enumsrequires scopes because it returns type “Enum”, which requires the scopes"read:enum".Query.interfacesrequires scopes because it returns type “Interface”, which requires the scopes"read:interface".Query.objectAs.enumrequires scopes because it returns type “Enum”, which requires the scopes"read:enum".Query.objectAs.scalarrequires scopes because it returns type “Scalar”, which requires the scopes"read:scalar".Query.objectBsrequires scopes because it returns type “ObjectB”, which requires the scopes"read:object".Query.scalarsrequires scopes because it returns type “Scalar”, which requires the scopes"read:scalar".
Federation
The@requiresScopes directive will always persist in the federated schema.
Shared fields
If@requiresScopes is declared on a field definition in one subgraph, and another instance of the same
field definition (a shared field) is defined in another subgraph without @requiresScopes, then @requiresScopes
will still be declared on the federated field.
This also means that selecting this field will always require the defined scopes, regardless of whether it would be
resolved from a subgraph that did not declare @requiresScopes.
This is shown in the example below:
Combining scopes in the same subgraph
When scopes are defined in multiple places (for example, on a field and on its return type), each set of scopes is combined with every set from the other definition. Algorithm- Take each set of scopes from the first definition.
- Combine it with each set from the second definition.
- Merge the scopes in each pair into a single AND set.
Simple example
[["read:query"]]
Type scopes: [["read:scalar"]]
Result: [["read:query", "read:scalar"]]
Selecting Query.scalars requires both "read:query" AND "read:scalar".
Multiple OR scopes
[["read:query"], ["read:private"]]
Type scopes: [["read:scalar"]]
Result:
"read:query" AND "read:scalar") OR ("read:private" AND "read:scalar").
Full example
This is effectively the same as:
Combining scopes across subgraphs
When multiple instances of a shared field or type define scopes across different subgraphs, the same combination rule applies—each set of scopes from one subgraph is combined with every set from the other. Consider the following subgraphs:Combining scopes (superset reduction)
After scopes are combined, any scope set that is a superset of another set is removed. A superset is redundant because the smaller set already grants access with fewer permissions. Consider the following subgraphs:
After reduction:
["read:id", "read:field"]and["read:field", "read:id"]are duplicates and supersets of both["read:id"]and["read:field"]- removed.["read:private", "read:id"]is a superset of["read:id"]- removed.["read:private", "read:field"]is a superset of["read:field"]- removed.
Errors
In the event that an agent without relevant permissions selects a non-nullable field that is declared with@requiresScopes, an authorization error will be returned, and the entire data will be null
(see Non-nullable authenticated data requested among unauthenticated data).
@requiresScopes, an authorization error will be returned, and the specific field will be null
(see Partial data):
Partial data (nullable data requiring permissions)
Imagine an agent without relevant permissions selects a field that is declared with @requiresScopes and the response type of that field is nullable. However, the agent also selects a field that is not declared @requiresScopes (nor are any potential nested fields). In this event, an authorization error will still be returned, but the specific data that requires authentication will be null, while the data not requiring authentication will be returned. Consider the following federated graph and corresponding query:Non-nullable data requiring scopes requested among data not requiring scopes
In the event an agent without relevant permissions selects any non-nullable fields that declare@requiresScopes (and
therefore require one or more permissions), an authorization error will be returned, and the entire data will
return null.
This is true even if one or more field selections did not require permissions or are nullable.
Consider the following federated graph and corresponding query:
"read:int" permission sending the query above would receive something like the following:
Partial permissions
An agent must have all relevant permissions within at least one entire set of AND scopes among the OR scopes declared through@requiresScopes for a selected field to return data.
In the event that the agent has some but not all permissions, the error message will be transparent: