graphql

GraphQL query parsing and analysis for authorization policies.

GraphQL Function Library for SAPL

Parses GraphQL queries and extracts security metrics for authorization policy decisions.

Basic Usage

var gql = graphql.validateQuery(resource.query, resource."schema");

// Access properties directly
gql.valid                   // boolean - query validity
gql.fields                  // array - all field names
gql.depth                   // integer - maximum nesting depth
gql.operation               // string - operation type (query/mutation/subscription)
gql.complexity              // integer - complexity score

// Security metrics
gql.security.aliasCount              // integer - aliased field count
gql.security.batchingScore           // integer - batching attack indicator
gql.security.maxPaginationLimit      // integer - highest pagination limit
gql.security.hasCircularFragments    // boolean - circular fragment detection
gql.security.isIntrospection         // boolean - introspection query
gql.security.directiveCount          // integer - directive count
gql.security.directivesPerField      // number - average directives per field

// AST details
gql.ast.operationName       // string - operation name
gql.ast.types               // array - types used
gql.ast.variables           // object - variable definitions
gql.ast.arguments           // object - field arguments
gql.ast.fragments           // object - fragment definitions
gql.ast.directives          // array - directive details

Functions

validateQuery

graphql.validateQuery(TEXT query, TEXT schema) -> OBJECT

Parses and validates a GraphQL query against a schema. Returns object with all security metrics.

Example:

policy "validate-graphql-query"
permit action == "execute";
  var gql = graphql.validateQuery(resource.query, resource."schema");
  gql.valid && gql.depth <= 5 && !("ssn" in gql.fields);

analyzeQuery

graphql.analyzeQuery(TEXT query) -> OBJECT

Parses a GraphQL query without schema validation. Returns same metrics as validateQuery() but valid only checks syntax.

Example:

policy "analyze-query-structure"
permit action == "execute";
  var gql = graphql.analyzeQuery(resource.query);
  gql.depth <= 5 && gql.security.aliasCount <= 10;

complexity

graphql.complexity(OBJECT parsed, OBJECT fieldWeights) -> NUMBER

Calculates weighted complexity using custom field weights. Unweighted fields default to 1.

Example:

var gql = graphql.validateQuery(resource.query, resource."schema");
var weights = {"posts": 5, "comments": 3, "user": 1};
graphql.complexity(gql, weights) <= 200;

parseSchema

graphql.parseSchema(TEXT schema) -> OBJECT

Parses and validates a GraphQL schema definition.

Common Use Cases

Field-Level Access Control

policy "restrict-pii-fields"
deny action == "execute";
  var gql = graphql.validateQuery(resource.query, resource."schema");
  var piiFields = ["ssn", "creditCard", "taxId"];
  array.containsAny(gql.fields, piiFields);

Depth and Complexity Limiting

policy "enforce-limits"
permit action == "execute";
  var gql = graphql.validateQuery(resource.query, resource."schema");
  gql.valid && gql.depth <= 5 && gql.complexity <= 100;

Operation Type Control

policy "mutations-require-admin"
permit action == "execute";
  var gql = graphql.validateQuery(resource.query, resource."schema");
  gql.operation != "mutation" || subject.role == "admin";

Batching Attack Prevention

policy "prevent-batching"
deny action == "execute";
  var gql = graphql.validateQuery(resource.query, resource."schema");
  gql.security.aliasCount > 10 || gql.security.batchingScore > 50;

Comprehensive Security

policy "comprehensive-security"
permit action == "execute";
  var gql = graphql.validateQuery(resource.query, resource."schema");
  gql.valid &&
  gql.depth <= 5 &&
  gql.fieldCount <= 50 &&
  gql.security.aliasCount <= 10 &&
  gql.security.maxPaginationLimit <= 100 &&
  !gql.security.hasCircularFragments &&
  !gql.security.isIntrospection &&
  !("ssn" in gql.fields);

Multiple operations

A document may declare several named operations; the one executed is chosen at request time by the operationName parameter, which this analysis does not observe. The security metrics (depth, fields, complexity, security.*) therefore describe the worst case across every operation in the document: the maximum depth and pagination limit, the union of all field names, and the logical OR of the introspection and circular-fragment flags. The descriptive operation, ast.operationName and ast.variables fields reflect the first operation in source order. When a document may carry more than one operation, gate on the aggregate security metrics rather than on the descriptive operation fields.

Error Handling

Invalid queries set valid to false with errors in errors array. Check valid before using other metrics.

Limits

To bound memory and computation on untrusted input, the following limits apply:

  • Reported query depth is capped at 100. The depth metric never exceeds this value regardless of how deeply the query or its operations nest, so depth comparisons in policies saturate at 100.
  • A schema passed to validateQuery or parseSchema may be at most 512 KB (524288 bytes). A larger schema is rejected with an error.

These limits apply because this input may originate from the authorization subscription or from policy information points, which are not vetted to the same degree as the policies and variables shipped with the PDP configuration.


complexity

graphql.complexity(OBJECT parsed, OBJECT fieldWeights) -> NUMBER

Calculates weighted complexity with custom field weights.

Example:

var gql = graphql.validateQuery(resource.query, resource."schema");
var weights = {"posts": 5, "comments": 3};
graphql.complexity(gql, weights) <= 200;

validateQuery

graphql.validateQuery(TEXT query, TEXT schema) -> OBJECT

Parses and validates a GraphQL query against a schema.

Returns comprehensive security analysis including validation, field extraction, complexity metrics, and potential security concerns.

Example:

var gql = graphql.validateQuery(resource.query, resource."schema");
gql.valid && gql.depth <= 5 && !("ssn" in gql.fields);

analyzeQuery

graphql.analyzeQuery(TEXT query) -> OBJECT

Parses a GraphQL query without schema validation. Only validates syntax.

Example:

var gql = graphql.analyzeQuery(resource.query);
gql.depth <= 5 && gql.security.aliasCount <= 10;

parseSchema

graphql.parseSchema(TEXT schema) -> OBJECT

Parses and validates a GraphQL schema definition.

Example:

var schemaResult = graphql.parseSchema(resource."schema");
schemaResult.valid;