# GraphQL Federation Security API > Compare authorization directives and deployment configuration across caller-supplied GraphQL Federation subgraphs. No gateway is contacted. Each POST has a fixed USDC price on Base, paid with the x402 exact scheme. The request is validated first, and payment settles only after a successful (2xx) result. Failed calls are not charged. 1. POST JSON matching the requestBody. Invalid input returns 400 with no payment challenge. 2. A valid unpaid call returns 402 with the exact amount and payTo. 3. Pay and retry with payment-signature. Payment settles only if the operation returns 2xx. A 4xx/5xx is not charged. - Product: https://www.brainiac.software/api/graphql-security - Docs: https://www.brainiac.software/api/graphql-security/docs - OpenAPI: https://www.brainiac.software/api/graphql-security/openapi.json - Contact: support@brainiac.software (https://www.brainiac.software/contact) ## Operations ### POST /api/v1/graphql-security/federation-authorization-audit $0.05 USDC. 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. Inputs: subgraphs, authorizationDirectives?, expected?, supergraph? Docs: https://www.brainiac.software/api/graphql-security/docs#graphql-security-federation-authorization-audit Example request: ```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}" } ] } ``` Example response: ```json { "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." ] } ``` ### POST /api/v1/graphql-security/field-authorization-coverage $0.04 USDC. 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. Inputs: protected_directives, subgraphs Docs: https://www.brainiac.software/api/graphql-security/docs#graphql-security-field-authorization-coverage Example request: ```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}" } ] } ``` Example response: ```json { "authorization_coverage_score": 60, "unprotected_fields_percentage": 40 } ``` ### POST /api/v1/graphql-security/federation-subgraph-exposure-audit $0.05 USDC. 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. Inputs: subgraphs, router?, networkRules?, publicEndpoints? Docs: https://www.brainiac.software/api/graphql-security/docs#graphql-security-federation-subgraph-exposure-audit Example request: ```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": [] } ``` Example response: ```json { "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." ] } ``` ### POST /api/v1/graphql-security/subgraph-complexity $0.04 USDC. 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. Inputs: sdl, max_depth, introspection Docs: https://www.brainiac.software/api/graphql-security/docs#graphql-security-subgraph-complexity Example request: ```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" } ``` Example response: ```json { "exposure_risk_score": 85, "max_query_complexity_index": 2 } ```