## Minimum requirements

| Package | Minimum version |
| --- | --- |
| controlplane | [0.58.0](https://github.com/wundergraph/cosmo/releases/tag/controlplane%400.58.0) |
| router | [0.60.0](https://github.com/wundergraph/cosmo/releases/tag/router%400.60.0) |
| wgc | [0.39.0](https://github.com/wundergraph/cosmo/releases/tag/wgc%400.39.0) |

Make sure you have correctly set up [Authentication & Authorization](https://cosmo-docs.wundergraph.com/router/authentication-and-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](https://cosmo-docs.wundergraph.com/federation/directives/requiresscopes#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](https://cosmo-docs.wundergraph.com/federation/directives/requiresscopes#partial-data-nullable-authenticated-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
  }
}
```
