@requiresScopes - WunderGraph

Minimum requirements

Package Minimum version
controlplane 0.58.0
router 0.60.0
wgc 0.39.0

Make sure you have correctly set up Authentication & Authorization.

Definition

directive @requiresScopes(
    scopes: [[openfed__Scope!]!]!
) on ENUM | FIELD_DEFINITION | INTERFACE | OBJECT | SCALAR

scalar openfed__Scope

Arguments

Argument Name Argument Type
scopes [[openfed__Scope!]!]!

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:

type Query {
  a: String! @requiresScopes(scopes: [["read:field"], ["read:scalar"]])
}

If an agent wished to select Query.a, it would require EITHER the "read:field" permission OR the "read:scalar" permission.

AND Scopes

Consider the following @requiresScopes declared on Query.b:

type Query {
  b: String! @requiresScopes(scopes: [["read:field", "read:scalar"]])
}

If an agent wished to select 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:

type Query {
  c: String! @requiresScopes(scopes: [[
    ["read:field", "read:scalar"],
    ["read:query", "read:private"],
    ["read:all"]
  ])
}

If an agent wished to select 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 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:

type Query {
  ids: [ID!]! @requiresScopes(scopes: [["read:id"]])
  names: [String!]!
}

The field Query.ids would be protected in the following operation:

query {
  ids # requires scopes "read:id"
  names # does not require any scopes
}

The behavior is similar for Interfaces.

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).

{
"errors":[{
  "message":"Unauthorized to load field 'Query.enumField'. Reason: required scopes: ('read:enum' AND 'read:field') OR ('read:all'), actual scopes: <none>",
  "path":["enumField"]
}],
  "data":null
}

In the event that an agent without relevant permissions selects a nullable field that is declared with @requiresScopes, an authorization error will be returned, and the specific field will be null (see Partial data):

{
"errors":[{
  "message":"Unauthorized to load field 'Query.enumField'. Reason: required scopes: ('read:enum' AND 'read:field') OR ('read:all'), actual scopes: <none>",
  "path":["enumField"]
}],
  "data":{
    "enumField":null
  }
}