TLDR
@requires isn’t just a helper directive. In practice, it can leak sensitive fields across subgraphs and create compliance headaches. The @openfed__requireFetchReasons directive fixes this by making fetch reasons explicit and giving subgraphs control over who can access sensitive fields.
The Real Problem with @requires
Most of us use @requires without a second thought. It’s convenient, and it works. But in a federated setup, it can quietly bypass the data boundaries you think are in place.
From a compliance angle, that’s dangerous. The audit team might assume a field is locked down, but another subgraph could still access it by tacking on a @requires. That’s how sensitive data ends up in places it shouldn’t.
Example: An Auction Service with a Leak
Here’s a stripped-down case. A fictional company, LeeWay, lets people auction off their old software. Two subgraphs handle the logic:
- Auction subgraph defines the auction and its sensitive minimumPrice.
- Description subgraph extends the type with a description field that uses @requires.
# Auction Subgraph
type Query {
auction(id: ID!): Auction!
}
type Auction @key(fields: "id") {
id: ID!
title: String!
minimumPrice: Int!
}
# Description Subgraph with exploitable directives.
type Auction @key(fields: "id") {
id: ID!
minimumPrice: Int! @external
description: String! @requires(fields: "minimumPrice")
}
Now if a client asks for description, the Router will fetch minimumPrice from the Auction subgraph and pass it along:
{
"query": "query($representations: [_Any!]!) { _entities(representations: $representations) { ... on Auction { description } } }",
"variables": {
"representations": [
{ "__typename": "Auction", "id": "1", "minimumPrice": 100 }
]
}
}
Suddenly, minimumPrice is exposed. Authorization checks still exist, but compliance controls are broken because another subgraph now has access.
Fixing It with @openfed__requireFetchReasons
WunderGraph’s @openfed__requireFetchReasons directive locks this down. You apply it to the sensitive field:
# Auction Subgraph
type Query {
auction(id: ID!): Auction!
}
type Auction @key(fields: "id") {
id: ID!
title: String!
minimumPrice: Int! @openfed__requireFetchReasons
}
With the directive, the Router includes fetch reasons in the extensions field:
{
"extensions": {
"fetch_reasons": [
{
"typename": "Auction",
"field": "minimumPrice",
"by_subgraphs": ["Description"],
"is_requires": true
}
]
}
}
The Auction subgraph can then parse this and decide: is the Description subgraph allowed to fetch this field? If not, deny it.
To cover direct user access, the Router adds a by_user flag:
{
"extensions": {
"fetch_reasons": [
{
"typename": "Auction",
"field": "minimumPrice",
"by_user": true
}
]
}
}
That way, you can distinguish between a legitimate client request and a dependency from another subgraph.
Compliance and Audit Benefits
This isn’t just about passing audits. The directive makes sensitive data access explicit, declarative, and auditable. Without safeguards, @requires can expose sensitive fields to other subgraphs.
With @openfed__requireFetchReasons, you don’t have to guess. The schema itself carries the compliance rules, and the runtime enforces them.
Wrap-Up
If you’re working with GraphQL Federation and care about data boundaries, don’t ignore @requires. It can punch holes in your compliance story. The @openfed__requireFetchReasons directive gives you a clean, declarative way to control fetch reasons and build trust into your schema.
Originally posted on WunderGraph’s blog
Top comments (0)