Field-Level Data Obfuscation for GraphQL | Cosmo by WunderGraph - WunderGraph
Mask sensitive GraphQL fields by role, without touching subgraphs
Cosmo Router Custom Modules let you intercept and obfuscate GraphQL response fields at the router level. Different users see different data. No subgraph code changes.
Written in Go. Field-level. Applied per request.
The problem
The same API serves users who should see different data
Field-level access control is real work. Doing it in every subgraph is fragile and expensive to maintain.
Different users need different data visibility
A developer debugging a query should not see real customer names or payment data. A data scientist needs realistic data shapes but not the actual PII. The same API serves both.
Subgraph-level masking requires code changes everywhere
Adding field-level obfuscation in each subgraph means touching every service, syncing release cycles, and maintaining that logic as schemas evolve.
AI systems should not read sensitive fields
When GraphQL APIs are exposed to AI models or third-party systems, fields like SSNs, credit card numbers, and medical data must be protected without duplicating the API.
Our solution
Field-level obfuscation at the router
A Custom Module intercepts GraphQL response data before it reaches the client. The renderer replaces field values based on user role or request context. Subgraphs are unaware of the transformation.
How it works
- Implement a
CustomFieldValueRendererinterface in a Cosmo Router Custom Module, written in Go. - The renderer receives each field value with its GraphQL type (String, Int, Float, or custom) and can transform or replace it.
- Use the
RouterOnRequesthook to select different renderers based on authentication claims, user roles, or request headers. - A developer with the "developer" role gets all String fields replaced with "xxx" and numeric fields with placeholders, preserving the response structure.
- An AI system identified by a specific header receives placeholder values for any field marked sensitive, while the rest of the response is unaffected.
- No subgraph code changes are required. The obfuscation layer lives entirely at the router.
Before & After
| Before Cosmo | With Cosmo |
|---|---|
| Data masking implemented separately in each subgraph | Centralized obfuscation at the router, applied to all subgraphs |
| Complex authorization logic in every resolver | Role-based obfuscation via authentication claims and request context |
| Separate data pipelines for AI and analytics access | Same API with dynamic field filtering per request context |
| Code changes required to add or change privacy rules | Custom Module update without touching subgraph implementations |
Field value renderer interface
func (c *CustomValueRenderer) RenderFieldValue(
ctx *resolve.Context,
value resolve.FieldValue,
out io.Writer,
) error {
switch value.Type {
case "String":
_, err = out.Write([]byte(`"xxx"`))
case "Int", "Float":
_, err = out.Write([]byte(`123`))
default:
_, err = out.Write(value.Data)
}
return err
}
How field-level obfuscation works in Cosmo Router
01
Intercept
The router processes the GraphQL response from subgraphs before sending it to the client. The Custom Module intercepts each field value at this point.
02
Identify
The RouterOnRequest hook reads authentication claims, user roles, or request headers to determine which renderer to apply for this request.
03
Transform
The CustomFieldValueRenderer receives each field with its type information and writes the obfuscated value. String fields become "xxx"; numeric fields become placeholder values.
04
Return
The client receives a structurally complete response. Types, field names, and nesting are preserved. Only the values that match the obfuscation rules are replaced.
Fine-grained control at the gateway
Centralized privacy control
Implement obfuscation once at the router. All subgraphs behind it inherit the protection without any code changes.
Role-based obfuscation
Apply different rendering rules per request based on authentication claims, user roles, or any request context your Custom Module can read.
AI-safe API access
Protect sensitive fields when exposing your GraphQL API to AI models or third-party integrations. The model gets realistic response shapes with placeholders for protected fields.
No subgraph changes
Add, change, or remove privacy rules by updating the Custom Module. Subgraph code and schemas stay untouched.
Add field-level privacy to your GraphQL API
Implement a Custom Module renderer. Apply it at the router. Subgraphs stay unchanged.
FAQ
Advanced data privacy on Cosmo Router
- What is a CustomFieldValueRenderer?
- How does the router know which renderer to use for a given request?
- Which field types can be obfuscated?
- Does the response structure change after obfuscation?
- What language do Custom Modules use?
- Is this available on all plans?
Full implementation guide in the advanced data privacy documentation.