You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 13e0479
Browse filesBrowse the repository at this point in the historyBrowse files
User-filtered SDL: keep the output self-consistent, share it with introspection
Review of #571 found filtered SDL could name types it never defines: a type
emptied by field-level auth, a protected interface in implements, a visible
field with a protected argument type, and an empty query root.
SchemaVisibility now computes the hidden types once per request context and
repeats until stable: a type the filtering empties is hidden, a field is hidden
if it is protected or its return or any argument type is hidden, and hidden
interfaces/union members are filtered from their lists. The query root always
stays (output with no field block when empty). Introspection uses the same set,
so __schema, __type and SDL agree.
Also: default interface methods on ISchemaProvider so implementers do not
break, ToGraphQLSchemaStringAsync(ClaimsPrincipal) using the schema's own
AuthorizationService, the SchemaIntrospection.Make doc comment fixed, and tests
that assert every referenced type is defined.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: CHANGELOG.md
+2-1Lines changed: 2 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -2,7 +2,8 @@
2
2
3
3
## Changes
4
4
5
-
-`ToGraphQLSchemaString(QueryRequestContext? requestContext, bool includeDescriptions = true)` outputs SDL containing only the types and fields the user in the request context is authorized to access - the same rules introspection applies (protected types, and fields that are protected or return a protected type, are left out; the mutation/subscription root is omitted when none of its fields are visible). Useful for handing a schema to a user or AI agent (e.g. an MCP server tool) where SDL is more compact than introspection. `ToGraphQLSchemaString()` without a context still outputs the full schema.
5
+
-`ToGraphQLSchemaStringAsync(ClaimsPrincipal? user)` (and `ToGraphQLSchemaString(QueryRequestContext? requestContext)`) output SDL containing only what that user may access, using the schema's `AuthorizationService` as query execution does. The result is self-consistent: a type the filtering leaves empty is hidden along with the fields returning it, a field is hidden when an argument's type is hidden, and hidden interfaces and union members are dropped from `implements` and union lists. Useful for handing a schema to a user or AI agent (e.g. an MCP server tool) where SDL is more compact than introspection. `ToGraphQLSchemaString()` without a user still outputs the full schema. Both are default interface methods on `ISchemaProvider`, so custom implementations do not break.
6
+
- Introspection for a user now hides the same things the SDL does. Previously a type with no type-level authorization but every field protected was still listed (with `fields: []`), a field taking an argument of a protected enum or input type was listed, and protected interfaces still appeared in `interfaces`. These are now hidden, so a client building a schema from introspection gets a valid one. Introspection without a user is unchanged.
6
7
-`[Required]` on an argument (a property/field of an arguments object or a method parameter) now behaves like `ArgumentHelper.Required<T>()` - the argument has no default value and must be provided by the query. Previously a value type kept its implicit `default(T)` as the schema default, so `[Required] int Take` printed `take: Int! = 0` (optional for clients) and a query leaving it out ran with `0`. It is now `take: Int!` and leaving it out is a `missing required argument` error. Remove `[Required]` if you relied on the old default.
7
8
- Introspection `__InputValue.defaultValue` no longer strips the quotes off string-like defaults. The spec defines it as the GraphQL literal, so a string default of `hello` is now returned as `"hello"` - the same text as in the SDL. Clients building a schema from introspection (`buildClientSchema`, GraphiQL, codegen against an endpoint) previously dropped such defaults or failed to parse them (`Guid`, strings with spaces). If you read `defaultValue` directly as text rather than parsing it as GraphQL, string defaults now include their quotes.
Copy file name to clipboardExpand all lines: docs/docs/authorization.md
+4-3Lines changed: 4 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -65,13 +65,14 @@ Introspection queries (`__schema` and `__type`) respect authorization — the re
65
65
66
66
`schema.ToGraphQLSchemaString()` always outputs the full schema — use it to generate SDL files for tooling and type generation.
67
67
68
-
To get SDL filtered for a user, pass a `QueryRequestContext`. The same rules as introspection apply: protected types are left out, as are fields that are protected or return a protected type.
68
+
To get SDL filtered for a user, use `ToGraphQLSchemaStringAsync(user)`. It uses the schema's `AuthorizationService` exactly as query execution does, and applies the same rules as introspection.
The result is self-consistent SDL: nothing in it refers to a type it does not define. Protected types are left out, as are fields that are protected, return a hidden type or take an argument of a hidden type. A type whose fields are all hidden is itself hidden, which can in turn hide the fields returning it. Protected interfaces are dropped from `implements` lists, and protected types from union member lists. The query root always stays, even with no visible fields. Introspection hides exactly the same types and fields, so `__schema`, `__type` and the SDL agree.
75
+
75
76
This is useful when handing a schema to a person or an AI agent (e.g. an MCP server tool), where fields they cannot query are noise or information they should not have. SDL is far more compact than an introspection result for the same information.
/// <summary>SDL with only what <paramref name="user"/> may see, filtered by this schema's AuthorizationService. See SchemaProvider for details.</summary>
0 commit comments