Skip to content

Conversation

@knope-bot
Copy link
Contributor

@knope-bot knope-bot bot commented Nov 21, 2025

Important

Merging this pull request will create these releases

query-planner 2.1.0 (2025-11-24)

Features

Directive-Based Authorization

Introducing directive-based authorization. This allows you to enforce fine-grained access control directly from your subgraph schemas using the @authenticated and @requiresScopes directives.

This new authorization layer runs before the query planner, ensuring that unauthorized requests are handled efficiently without reaching your subgraphs.

Configuration

You can configure how the router handles unauthorized requests with two modes:

  • filter (default): Silently removes any fields the user is not authorized to see from the query. The response will contain null for the removed fields and an error in the errors array.
  • reject: Rejects the entire GraphQL operation if it requests any field the user is not authorized to access.

To configure this, add the following to your router.yaml configuration file:

authentication:
  directives:
    unauthorized:
      # "filter" (default): Removes unauthorized fields from the query and returns errors.
      # "reject": Rejects the entire request if any unauthorized field is requested.
      mode: reject

If this section is omitted, the router will use filter mode by default.

JWT Scope Requirements

When using the @requiresScopes directive, the router expects the user's granted scopes to be present in the JWT payload. The scopes should be in an array of strings or a string (scopes separated by space), within a claim named scope.

Here is an example of a JWT payload with the correct format:

{
  "sub": "user-123",
  "scope": [
    "read:products",
    "write:reviews"
  ],
  "iat": 1516239022
}

Fixes

Avoid extra query prefix for anonymous queries

When there is no variable definitions and no operation name, GraphQL queries can be sent without the query prefix. For example, instead of sending:

- query {
+ {
  user(id: "1") {
    name
  }
}

config 0.0.12 (2025-11-24)

Features

Breaking

Removed pool_idle_timeout_seconds from traffic_shaping, instead use pool_idle_timeout with duration format.

traffic_shaping:
-  pool_idle_timeout_seconds: 30
+  pool_idle_timeout: 30s

#540 by @ardatan

node-addon 0.0.4 (2025-11-24)

Fixes

Avoid extra query prefix for anonymous queries

When there is no variable definitions and no operation name, GraphQL queries can be sent without the query prefix. For example, instead of sending:

- query {
+ {
  user(id: "1") {
    name
  }
}

executor 6.1.0 (2025-11-24)

Features

Directive-Based Authorization

Introducing directive-based authorization. This allows you to enforce fine-grained access control directly from your subgraph schemas using the @authenticated and @requiresScopes directives.

This new authorization layer runs before the query planner, ensuring that unauthorized requests are handled efficiently without reaching your subgraphs.

Configuration

You can configure how the router handles unauthorized requests with two modes:

  • filter (default): Silently removes any fields the user is not authorized to see from the query. The response will contain null for the removed fields and an error in the errors array.
  • reject: Rejects the entire GraphQL operation if it requests any field the user is not authorized to access.

To configure this, add the following to your router.yaml configuration file:

authentication:
  directives:
    unauthorized:
      # "filter" (default): Removes unauthorized fields from the query and returns errors.
      # "reject": Rejects the entire request if any unauthorized field is requested.
      mode: reject

If this section is omitted, the router will use filter mode by default.

JWT Scope Requirements

When using the @requiresScopes directive, the router expects the user's granted scopes to be present in the JWT payload. The scopes should be in an array of strings or a string (scopes separated by space), within a claim named scope.

Here is an example of a JWT payload with the correct format:

{
  "sub": "user-123",
  "scope": [
    "read:products",
    "write:reviews"
  ],
  "iat": 1516239022
}

Breaking

Removed pool_idle_timeout_seconds from traffic_shaping, instead use pool_idle_timeout with duration format.

traffic_shaping:
-  pool_idle_timeout_seconds: 30
+  pool_idle_timeout: 30s

#540 by @ardatan

router 0.0.20 (2025-11-24)

Features

Directive-Based Authorization

Introducing directive-based authorization. This allows you to enforce fine-grained access control directly from your subgraph schemas using the @authenticated and @requiresScopes directives.

This new authorization layer runs before the query planner, ensuring that unauthorized requests are handled efficiently without reaching your subgraphs.

Configuration

You can configure how the router handles unauthorized requests with two modes:

  • filter (default): Silently removes any fields the user is not authorized to see from the query. The response will contain null for the removed fields and an error in the errors array.
  • reject: Rejects the entire GraphQL operation if it requests any field the user is not authorized to access.

To configure this, add the following to your router.yaml configuration file:

authentication:
  directives:
    unauthorized:
      # "filter" (default): Removes unauthorized fields from the query and returns errors.
      # "reject": Rejects the entire request if any unauthorized field is requested.
      mode: reject

If this section is omitted, the router will use filter mode by default.

JWT Scope Requirements

When using the @requiresScopes directive, the router expects the user's granted scopes to be present in the JWT payload. The scopes should be in an array of strings or a string (scopes separated by space), within a claim named scope.

Here is an example of a JWT payload with the correct format:

{
  "sub": "user-123",
  "scope": [
    "read:products",
    "write:reviews"
  ],
  "iat": 1516239022
}

Breaking

Removed pool_idle_timeout_seconds from traffic_shaping, instead use pool_idle_timeout with duration format.

traffic_shaping:
-  pool_idle_timeout_seconds: 30
+  pool_idle_timeout: 30s

#540 by @ardatan

Fixes

Avoid extra query prefix for anonymous queries

When there is no variable definitions and no operation name, GraphQL queries can be sent without the query prefix. For example, instead of sending:

- query {
+ {
  user(id: "1") {
    name
  }
}

@github-actions
Copy link

github-actions bot commented Nov 21, 2025

k6-benchmark results

     ✓ response code was 200
     ✓ no graphql errors
     ✓ valid response structure

     █ setup

     checks.........................: 100.00% ✓ 204078      ✗ 0    
     data_received..................: 6.0 GB  199 MB/s
     data_sent......................: 80 MB   2.7 MB/s
     http_req_blocked...............: avg=3.84µs   min=661ns   med=1.89µs  max=7.02ms   p(90)=2.74µs  p(95)=3.16µs  
     http_req_connecting............: avg=1.11µs   min=0s      med=0s      max=3.3ms    p(90)=0s      p(95)=0s      
     http_req_duration..............: avg=21.59ms  min=2.18ms  med=20.55ms max=209.68ms p(90)=29.37ms p(95)=32.8ms  
       { expected_response:true }...: avg=21.59ms  min=2.18ms  med=20.55ms max=209.68ms p(90)=29.37ms p(95)=32.8ms  
     http_req_failed................: 0.00%   ✓ 0           ✗ 68046
     http_req_receiving.............: avg=175.77µs min=25.58µs med=41.95µs max=181.03ms p(90)=95.18µs p(95)=398.18µs
     http_req_sending...............: avg=24.64µs  min=5.49µs  med=11.06µs max=22.05ms  p(90)=16.54µs p(95)=27.7µs  
     http_req_tls_handshaking.......: avg=0s       min=0s      med=0s      max=0s       p(90)=0s      p(95)=0s      
     http_req_waiting...............: avg=21.38ms  min=2.12ms  med=20.42ms max=57.42ms  p(90)=29.13ms p(95)=32.44ms 
     http_reqs......................: 68046   2263.481135/s
     iteration_duration.............: avg=22.04ms  min=5.95ms  med=20.92ms max=235.22ms p(90)=29.84ms p(95)=33.31ms 
     iterations.....................: 68026   2262.815855/s
     vus............................: 50      min=50        max=50 
     vus_max........................: 50      min=50        max=50 

@github-actions
Copy link

github-actions bot commented Nov 21, 2025

🐋 This PR was built and pushed to the following Docker images:

Image Names: ghcr.io/graphql-hive/router

Platforms: linux/amd64,linux/arm64

Image Tags: ghcr.io/graphql-hive/router:pr-583 ghcr.io/graphql-hive/router:sha-6489db9

Docker metadata
{
"buildx.build.ref": "builder-65d0cb29-db09-4ef5-ad0b-9d38c2a6e432/builder-65d0cb29-db09-4ef5-ad0b-9d38c2a6e4320/i0rdj2xc9vp2hbxw2s3vnrj56",
"containerimage.descriptor": {
  "mediaType": "application/vnd.oci.image.index.v1+json",
  "digest": "sha256:b618207e378a8e5588c47c56fa92598de975da1d9df1bea690f1109a2db32052",
  "size": 1609
},
"containerimage.digest": "sha256:b618207e378a8e5588c47c56fa92598de975da1d9df1bea690f1109a2db32052",
"image.name": "ghcr.io/graphql-hive/router:pr-583,ghcr.io/graphql-hive/router:sha-6489db9"
}

@knope-bot knope-bot bot force-pushed the knope/release branch 2 times, most recently from 972a341 to edc84d6 Compare November 24, 2025 10:41
@kamilkisiela kamilkisiela merged commit d1cf876 into main Nov 24, 2025
19 checks passed
@kamilkisiela kamilkisiela deleted the knope/release branch November 24, 2025 15:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant