https://www.brainiac.software/api/v1/graphql-security/federation-authorization-audit$0.05 USDCAudit federation authorization
Compare @authenticated, @requiresScopes, @policy, and caller-defined authorization directives across supplied subgraph SDL. @requires, @key, @external, @provides, and @shareable are inspected for schema-level differences. audit_status is clean, findings_detected, invalid, or incomplete. risk_level is low, medium, high, or critical. A difference is not a runtime authorization result. No gateway is contacted.
Body
| Field | Required | Notes |
|---|---|---|
subgraphs | Yes | array; Array |
authorizationDirectives | No | array; Array |
expected | No | array; Array |
supergraph | No | string |
Request exampleJSON
{
"subgraphs": [
{
"name": "accounts",
"federationVersion": "2.3",
"sdl": "extend schema @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@shareable\"])\ninterface Viewer { id: ID! }\ntype User implements Viewer @key(fields: \"id\") {\n id: ID!\n email: String @authenticated @shareable\n ssn: String @requiresScopes(scopes: [[\"pii\"]])\n}"
},
{
"name": "reviews",
"federationVersion": "2.3",
"sdl": "extend schema @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@external\", \"@requires\", \"@shareable\"])\ninterface Viewer { id: ID! @authenticated }\ntype User implements Viewer @key(fields: \"id\") {\n id: ID!\n email: String @external @shareable\n ssn: String @external\n review: String @requires(fields: \"email ssn\")\n}"
}
]
}Response exampleJSON
{
"audit_status": "findings_detected",
"risk_level": "critical",
"authorization_conflicts": [
{
"code": "requirement_differs",
"type": "Viewer",
"field": "id",
"subgraphs": [
"accounts",
"reviews"
],
"detail": "Viewer.id has different authorization directives across accounts (no supplied authorization requirement), reviews (authentication). This is a schema-level difference. No gateway was executed."
},
{
"code": "requirement_differs",
"type": "User",
"field": "email",
"subgraphs": [
"accounts",
"reviews"
],
"detail": "User.email has different authorization directives across accounts (authentication), reviews (no supplied authorization requirement). The field is marked @shareable. One declaration is @external. This is a schema-level difference. No gateway was executed."
},
{
"code": "requirement_differs",
"type": "User",
"field": "ssn",
"subgraphs": [
"accounts",
"reviews"
],
"detail": "User.ssn has different authorization directives across accounts (scopes pii), reviews (no supplied authorization requirement). One declaration is @external. This is a schema-level difference. No gateway was executed."
}
],
"transitive_dependency_findings": [
{
"subgraph": "reviews",
"type": "User",
"field": "review",
"requires": "email ssn",
"required_field": "email",
"detail": "reviews.User.review depends on email through @requires. accounts.User.email requires authentication, and the dependent field requires no supplied authorization requirement. This is a schema-level difference. No gateway was executed."
},
{
"subgraph": "reviews",
"type": "User",
"field": "review",
"requires": "email ssn",
"required_field": "ssn",
"detail": "reviews.User.review depends on ssn through @requires. accounts.User.ssn requires scopes pii, and the dependent field requires no supplied authorization requirement. This is a schema-level difference. No gateway was executed."
}
],
"interface_policy_mismatches": [
{
"subgraph": "reviews",
"interface": "Viewer",
"type": "User",
"field": "id",
"detail": "reviews.User.id implements Viewer.id. The interface field requires authentication, and the implementing field requires no supplied authorization requirement. This is a schema-level difference. No gateway was executed."
}
],
"shared_field_policy_mismatches": [
{
"type": "Viewer",
"field": "id",
"subgraphs": [
"accounts",
"reviews"
],
"detail": "Viewer.id has different authorization directives across accounts (no supplied authorization requirement), reviews (authentication). This is a schema-level difference. No gateway was executed."
},
{
"type": "User",
"field": "email",
"subgraphs": [
"accounts",
"reviews"
],
"detail": "User.email has different authorization directives across accounts (authentication), reviews (no supplied authorization requirement). The field is marked @shareable. One declaration is @external. This is a schema-level difference. No gateway was executed."
},
{
"type": "User",
"field": "ssn",
"subgraphs": [
"accounts",
"reviews"
],
"detail": "User.ssn has different authorization directives across accounts (scopes pii), reviews (no supplied authorization requirement). One declaration is @external. This is a schema-level difference. No gateway was executed."
}
],
"affected_subgraphs": [
{
"subgraph": "accounts",
"detail": "This subgraph is named by a schema-level authorization finding. No router was contacted."
},
{
"subgraph": "reviews",
"detail": "This subgraph is named by a schema-level authorization finding. No router was contacted."
}
],
"findings": [
{
"code": "weaker_dependent_field",
"severity": "critical",
"subgraph": "reviews",
"type": "User",
"field": "review",
"detail": "reviews.User.review depends on email through @requires. accounts.User.email requires authentication, and the dependent field requires no supplied authorization requirement. This is a schema-level difference. No gateway was executed."
},
{
"code": "weaker_dependent_field",
"severity": "critical",
"subgraph": "reviews",
"type": "User",
"field": "review",
"detail": "reviews.User.review depends on ssn through @requires. accounts.User.ssn requires scopes pii, and the dependent field requires no supplied authorization requirement. This is a schema-level difference. No gateway was executed."
},
{
"code": "interface_requirement_differs",
"severity": "high",
"subgraph": "reviews",
"type": "User",
"field": "id",
"detail": "reviews.User.id implements Viewer.id. The interface field requires authentication, and the implementing field requires no supplied authorization requirement. This is a schema-level difference. No gateway was executed."
},
{
"code": "shared_field_requirement",
"severity": "high",
"subgraph": "reviews",
"type": "Viewer",
"field": "id",
"detail": "Viewer.id has different authorization directives across accounts (no supplied authorization requirement), reviews (authentication). This is a schema-level difference. No gateway was executed."
},
{
"code": "shared_field_requirement",
"severity": "high",
"subgraph": "reviews",
"type": "User",
"field": "email",
"detail": "User.email has different authorization directives across accounts (authentication), reviews (no supplied authorization requirement). The field is marked @shareable. One declaration is @external. This is a schema-level difference. No gateway was executed."
},
{
"code": "shared_field_requirement",
"severity": "high",
"subgraph": "reviews",
"type": "User",
"field": "ssn",
"detail": "User.ssn has different authorization directives across accounts (scopes pii), reviews (no supplied authorization requirement). One declaration is @external. This is a schema-level difference. No gateway was executed."
},
{
"code": "schema_only",
"severity": "low",
"detail": "Only the supplied SDL was compared. No gateway or subgraph was executed, so this result is not a runtime authorization decision."
}
],
"limitations": [
"Schemas are the SDL strings in the request. No gateway, router, or subgraph was contacted.",
"A difference between directives is a schema-level inconsistency. It does not show that a request would be allowed or denied at runtime.",
"Known authorization directives are @authenticated, @requiresScopes, and @policy. Another directive is used only when the request supplies its semantics.",
"Scope and policy arguments are OR of AND groups. Order inside a group does not matter. A flat list is not treated as that shape.",
"@requires, @key, and @provides selections are read only when they contain field names and nested selections. Aliases, arguments, and fragments are not evaluated.",
"Type-level authorization directives apply to every field of that type in that subgraph.",
"Interface fields are compared only when both the interface and the implementing type declare the field.",
"The supergraph SDL is compared as supplied text. Federation composition was not executed."
]
}cURL
curl -i -X POST "https://www.brainiac.software/api/v1/graphql-security/federation-authorization-audit" \
-H 'content-type: application/json' \
-H 'Idempotency-Key: <fresh-64-character-random-hex-key>' \
--data-binary @- <<'JSON'
{
"subgraphs": [
{
"name": "accounts",
"federationVersion": "2.3",
"sdl": "extend schema @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@shareable\"])\ninterface Viewer { id: ID! }\ntype User implements Viewer @key(fields: \"id\") {\n id: ID!\n email: String @authenticated @shareable\n ssn: String @requiresScopes(scopes: [[\"pii\"]])\n}"
},
{
"name": "reviews",
"federationVersion": "2.3",
"sdl": "extend schema @link(url: \"https://specs.apollo.dev/federation/v2.3\", import: [\"@key\", \"@external\", \"@requires\", \"@shareable\"])\ninterface Viewer { id: ID! @authenticated }\ntype User implements Viewer @key(fields: \"id\") {\n id: ID!\n email: String @external @shareable\n ssn: String @external\n review: String @requires(fields: \"email ssn\")\n}"
}
]
}
JSONhttps://www.brainiac.software/api/v1/graphql-security/field-authorization-coverage$0.04 USDCScore field authorization coverage
Count object and interface fields in the supplied subgraph SDL and mark a field when its line, or its type line, contains one of the supplied directive names. Coverage is the share of marked fields. This is a text count. It does not compose a supergraph or decide whether a request would be allowed.
Body
| Field | Required | Notes |
|---|---|---|
protected_directives | Yes | array; Array |
subgraphs | Yes | array; Array |
Request exampleJSON
{
"protected_directives": [
"@authenticated"
],
"subgraphs": [
{
"name": "accounts",
"sdl": "type User @key(fields: \"id\") {\n id: ID!\n email: String @authenticated\n ssn: String\n}"
},
{
"name": "reviews",
"sdl": "type Review {\n id: ID! @authenticated\n body: String @authenticated\n}"
}
]
}Response exampleJSON
{
"authorization_coverage_score": 60,
"unprotected_fields_percentage": 40
}cURL
curl -i -X POST "https://www.brainiac.software/api/v1/graphql-security/field-authorization-coverage" \
-H 'content-type: application/json' \
-H 'Idempotency-Key: <fresh-64-character-random-hex-key>' \
--data-binary @- <<'JSON'
{
"protected_directives": [
"@authenticated"
],
"subgraphs": [
{
"name": "accounts",
"sdl": "type User @key(fields: \"id\") {\n id: ID!\n email: String @authenticated\n ssn: String\n}"
},
{
"name": "reviews",
"sdl": "type Review {\n id: ID! @authenticated\n body: String @authenticated\n}"
}
]
}
JSONhttps://www.brainiac.software/api/v1/graphql-security/federation-subgraph-exposure-audit$0.05 USDCAudit federation subgraph exposure
Compare caller-supplied subgraph endpoints, router authentication, network rules, and service or ingress labels with the intended public subgraph list. audit_status is clean, findings_detected, incomplete, or invalid. risk_level is low, medium, high, or critical. A public label is not evidence that an endpoint is reachable. No URL is probed.
Body
| Field | Required | Notes |
|---|---|---|
subgraphs | Yes | array; Array |
router | No | object; Object |
networkRules | No | array; Array |
publicEndpoints | No | array; Array |
Request exampleJSON
{
"subgraphs": [
{
"name": "accounts",
"endpoint": "http://accounts.cluster.local:4001/graphql",
"authentication": "required",
"acceptsDirectClients": false,
"introspection": false,
"developmentMode": false,
"service": {
"exposure": "cluster_local"
},
"ingress": {
"audience": "internal"
},
"federationFields": {
"service": "router_only",
"entities": "router_only"
}
},
{
"name": "reviews",
"endpoint": "https://reviews.example.com/graphql",
"authentication": "disabled",
"acceptsDirectClients": true,
"introspection": true,
"developmentMode": true,
"service": {
"exposure": "public"
},
"ingress": {
"audience": "public"
},
"federationFields": {
"service": "exposed",
"entities": "exposed"
}
}
],
"router": {
"authenticationToSubgraphs": "per_subgraph",
"introspection": false,
"sandbox": false
},
"networkRules": [
{
"subgraph": "accounts",
"source": "router",
"action": "allow"
},
{
"subgraph": "accounts",
"source": "public",
"action": "deny"
},
{
"subgraph": "reviews",
"source": "public",
"action": "allow"
}
],
"publicEndpoints": []
}Response exampleJSON
{
"audit_status": "findings_detected",
"risk_level": "critical",
"potentially_public_subgraphs": [
{
"subgraph": "reviews",
"reason": "service_public",
"host": "reviews.example.com",
"detail": "The supplied service exposure is public. This is a configuration label, not a live network observation."
},
{
"subgraph": "reviews",
"reason": "ingress_public",
"host": "reviews.example.com",
"detail": "The supplied ingress audience is public. This is a configuration label, not a live network observation."
},
{
"subgraph": "reviews",
"reason": "public_url_host",
"host": "reviews.example.com",
"detail": "The supplied endpoint host reviews.example.com is not a local, link-local, or private address. The host was not resolved or probed, so this is not evidence that it is reachable from the internet."
},
{
"subgraph": "reviews",
"reason": "direct_clients",
"host": "reviews.example.com",
"detail": "The supplied configuration says this subgraph accepts direct client traffic. This was not checked by opening a connection."
},
{
"subgraph": "reviews",
"reason": "network_allow",
"host": "reviews.example.com",
"detail": "A supplied network rule allows public or any source. This was not checked against a live firewall."
}
],
"internal_authentication_gaps": [
{
"subgraph": "reviews",
"source": "subgraph",
"detail": "The subgraph configuration sets authentication to disabled. The subgraph was not called."
}
],
"federation_internal_field_findings": [
{
"subgraph": "reviews",
"field": "_service",
"exposure": "exposed",
"detail": "The supplied policy marks _service as exposed. This was not checked by sending a query."
},
{
"subgraph": "reviews",
"field": "_entities",
"exposure": "exposed",
"detail": "The supplied policy marks _entities as exposed. This was not checked by sending a query."
}
],
"trust_boundary_violations": [
{
"subgraph": "reviews",
"configured": "service_public, ingress_public, public_url_host, direct_clients, network_allow",
"intended": "not_listed",
"detail": "reviews is not in publicEndpoints. The supplied configuration uses service_public, ingress_public, public_url_host, direct_clients, network_allow. This comparison uses only the request and does not show that the endpoint is reachable."
}
],
"findings": [
{
"code": "federation_field_exposed",
"severity": "high",
"subgraph": "reviews",
"field": "_service",
"detail": "The supplied policy marks _service as exposed. This was not checked by sending a query."
},
{
"code": "federation_field_exposed",
"severity": "high",
"subgraph": "reviews",
"field": "_entities",
"detail": "The supplied policy marks _entities as exposed. This was not checked by sending a query."
},
{
"code": "configured_public",
"severity": "high",
"subgraph": "reviews",
"detail": "The supplied service exposure is public. This is a configuration label, not a live network observation."
},
{
"code": "configured_public",
"severity": "high",
"subgraph": "reviews",
"detail": "The supplied ingress audience is public. This is a configuration label, not a live network observation."
},
{
"code": "configured_public",
"severity": "high",
"subgraph": "reviews",
"detail": "The supplied endpoint host reviews.example.com is not a local, link-local, or private address. The host was not resolved or probed, so this is not evidence that it is reachable from the internet."
},
{
"code": "configured_public",
"severity": "high",
"subgraph": "reviews",
"detail": "The supplied configuration says this subgraph accepts direct client traffic. This was not checked by opening a connection."
},
{
"code": "configured_public",
"severity": "high",
"subgraph": "reviews",
"detail": "A supplied network rule allows public or any source. This was not checked against a live firewall."
},
{
"code": "trust_boundary_violation",
"severity": "high",
"subgraph": "reviews",
"detail": "reviews is not in publicEndpoints. The supplied configuration uses service_public, ingress_public, public_url_host, direct_clients, network_allow. This comparison uses only the request and does not show that the endpoint is reachable."
},
{
"code": "authentication_disabled",
"severity": "high",
"subgraph": "reviews",
"detail": "The subgraph configuration sets authentication to disabled. The subgraph was not called."
},
{
"code": "introspection_enabled",
"severity": "high",
"subgraph": "reviews",
"detail": "The supplied configuration enables introspection. This was not checked by sending a query."
},
{
"code": "development_mode",
"severity": "high",
"subgraph": "reviews",
"detail": "The supplied configuration enables development mode. This was not checked against a running process."
},
{
"code": "authentication_inconsistent",
"severity": "high",
"detail": "The supplied authentication settings include disabled and required. This is a configuration difference, not a live authentication check."
},
{
"code": "configuration_only",
"severity": "low",
"detail": "This is a static reading of the supplied configuration. No URL was resolved or probed, and a public host name is not evidence of internet reachability."
}
],
"limitations": [
"This is a static reading of the supplied configuration. No URL was resolved, probed, or requested.",
"A public host name or a public exposure label is not evidence that the endpoint is reachable from the internet.",
"Missing fields are unknown. They are not treated as exposed or as protected.",
"Service exposure and ingress audience are explicit labels in the request. Kubernetes manifests, cloud security groups, and proxy files are not parsed.",
"_service and _entities are compared only with the supplied federationFields values.",
"publicEndpoints is a caller-supplied list of subgraph names. It was not checked against a live edge."
]
}cURL
curl -i -X POST "https://www.brainiac.software/api/v1/graphql-security/federation-subgraph-exposure-audit" \
-H 'content-type: application/json' \
-H 'Idempotency-Key: <fresh-64-character-random-hex-key>' \
--data-binary @- <<'JSON'
{
"subgraphs": [
{
"name": "accounts",
"endpoint": "http://accounts.cluster.local:4001/graphql",
"authentication": "required",
"acceptsDirectClients": false,
"introspection": false,
"developmentMode": false,
"service": {
"exposure": "cluster_local"
},
"ingress": {
"audience": "internal"
},
"federationFields": {
"service": "router_only",
"entities": "router_only"
}
},
{
"name": "reviews",
"endpoint": "https://reviews.example.com/graphql",
"authentication": "disabled",
"acceptsDirectClients": true,
"introspection": true,
"developmentMode": true,
"service": {
"exposure": "public"
},
"ingress": {
"audience": "public"
},
"federationFields": {
"service": "exposed",
"entities": "exposed"
}
}
],
"router": {
"authenticationToSubgraphs": "per_subgraph",
"introspection": false,
"sandbox": false
},
"networkRules": [
{
"subgraph": "accounts",
"source": "router",
"action": "allow"
},
{
"subgraph": "accounts",
"source": "public",
"action": "deny"
},
{
"subgraph": "reviews",
"source": "public",
"action": "allow"
}
],
"publicEndpoints": []
}
JSONhttps://www.brainiac.software/api/v1/graphql-security/subgraph-complexity$0.04 USDCScore subgraph query depth
Walk object-type references in the supplied SDL, starting at Query when that type is present. Scalars are ignored and a repeated type is not walked again. The index is that depth. The risk score rises when the depth passes the supplied limit, and when introspection is enabled. No router is contacted.
Body
| Field | Required | Notes |
|---|---|---|
sdl | Yes | string |
max_depth | Yes | integer |
introspection | Yes | string; One of: enabled, disabled |
Request exampleJSON
{
"sdl": "type Query {\n user: User\n}\ntype User {\n posts: [Post]\n}\ntype Post {\n author: User\n title: String\n}",
"max_depth": 1,
"introspection": "enabled"
}Response exampleJSON
{
"exposure_risk_score": 85,
"max_query_complexity_index": 2
}cURL
curl -i -X POST "https://www.brainiac.software/api/v1/graphql-security/subgraph-complexity" \
-H 'content-type: application/json' \
-H 'Idempotency-Key: <fresh-64-character-random-hex-key>' \
--data-binary @- <<'JSON'
{
"sdl": "type Query {\n user: User\n}\ntype User {\n posts: [Post]\n}\ntype Post {\n author: User\n title: String\n}",
"max_depth": 1,
"introspection": "enabled"
}
JSON